目录

  • 概述
  • http 服务端
  • http 客户端

1、概述

我们知道传统的 HTTP 服务器是由 AphcheNginxIIS 之类的软件来搭建的,但是 Nodejs 并不需要, Nodejs 提供了 http 模块,自身就可以用来构建服务器。http 模块内部封装了高效的 http 服务器 和 http 客户端。

http 模块提供两种使用方式:

  • 作为服务端使用时,创建一个 HTTP 服务器,监听 HTTP 客户端请求并返回响应。

  • 作为客户端使用时,发起一个 HTTP 客户端请求,获取服务端响应。

2、http 服务器

2.1 创建 http 服务器

一般是通过 http.createServer() 方法来创建一个 http 服务器,代码很简单,就那么几行就能实现:

const http = require('http');
http.createServer((request, response) => {response.writeHead(200, {'Content-Type': 'text-plain'});response.end('hello world');
}).listen(3000);

上述代码创建了一个服务器,监听了 3000 端口,访问 localhost: 3000 ,返回的信息是 hello world

2.2 请求信息 request 对象

继承于 http.IncomingMessag 类,是 http.server() 类的 request 事件的第一个参数,也即是 http.createServer(req, res) 的第一个参数。

HTTP请求本质上是一个数据流,由请求头(headers)和请求体(body)组成。例如以下是一个完整的HTTP请求数据内容。

POST / HTTP/1.1
User-Agent: curl/7.26.0
Host: localhost
Accept: */*
Content-Length: 11
Content-Type: application/x-www-form-urlencodedHello World

可以看到,空行之上是请求头,之下是请求体。HTTP 请求在发送给服务器时,可以认为是按照从头到尾的顺序一个字节一个字节地以数据流方式发送的。而 http 模块创建的 HTTP 服务器在接收到完整的请求头后,就会调用回调函数。

请求对象 resquest 包含有重要的信息:HTTP 版本,请求方法,请求地址,请求头部。

http.createServer((req, res) => {console.log('1.请求url:' + req.url);console.log('2.请求方法:' + req.method);console.log('3.HTTP 版本:' + req.httpVersion);console.log('4.请求头:' + JSON.stringify(req.headers));res.end('ok');
}).listen(3000);

在浏览器中打开 localhost: 3000 地址后,会输出一下内容:

1.请 url:/
2.请求方法:GET
3.HTTP 版本:1.1
4.请求头:{"host":"localhost:3000","connection":"keep-alive","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","accept-encoding":"gzip, deflate, br","accept-language":"zh-CN,zh;q=0.9,en;q=0.8","cookie":"_ga=GA1.1.1633526998.1530877254; ___rl__test__cookies=1532081765522"}

2.3 响应信息 response 对象

继承于 http.ServerResponse 类,是 http.server() 类的 request 事件的第二个参数,也即是 http.createServer(req, res) 的第二个参数。

HTTP 响应本质上也是一个数据流,同样由响应头(headers)和响应体(body)组成。例如以下是一个完整的HTTP请求数据内容。

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 11
Date: Tue, 05 Nov 2013 05:31:38 GMT
Connection: keep-aliveHello World

返回信息对象的内容包括:状态代码/状态描述信息、响应头部、响应主体。

2.3.1 设置状态代码、状态描述信息

res 提供了 res.writeHead()res.statusCode/res.statusMessage 来实现这个目的。

举例,如果想要设置 200/ok ,可以

res.writeHead(200, 'ok');

也可以

res.stateStatus = 200;
res.statusMessage = 'ok';

两者差不多,差异点在于:

  1. res.writeHead() 可以提供额外的功能,比如设置响应头部。
  2. 当响应头部发送出去后,res.statusCode/res.statusMessage 会被设置成已发送出去的 状态代码/状态描述信息。

2.3.2 设置响应头部

res 提供了 res.writeHead()response.setHeader() 来实现响应头部的设置。

举例,比如想把 Content-Type 设置为 text-plain,那么可以

// 方法一
res.writeHead(200, 'ok', {'Content-Type': 'text-plain'
});// 方法二
res.setHeader('Content-Type', 'text-plain');

两者的差异点在哪里呢?

  1. res.writeHead() 不单单是设置 header
  2. 已经通过 res.setHeader() 设置了 header,当通过 res.writeHead() 设置同名header,res.writeHead() 的设置会覆盖之前的设置。

2.3.3 设置响应主体

主要用到 res.write() 以及 res.end() 两个方法。

response.write(chunk[, encoding][, callback])

  • chunk:响应主体的内容,可以是 string,也可以是 buffer 。当为 string 时,encoding 参数用来指明编码方式。(默认是 utf8
  • encoding:编码方式,默认是 utf8
  • callback

response.end([data][, encoding][, callback])

该方法会通知服务器,所有响应头和响应主体都已被发送,即服务器将其视为已完成。 每次响应都必须调用 response.end() 方法。

如果指定了 data,则相当于调用 response.write(data, encoding) 之后再调用 response.end(callback)

如果指定了 callback,则当响应流结束时被调用。

2.4 获取 GET/POST 请求的内容

2.4.1 获取 GET 请求的内容

const http = require('http');
const url = require('url');http.createServer((req, res) => {res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});res.end(JSON.stringify(url.parse(req.url)));
}).listen(3000);

在浏览器中打开:http://localhost:3000/user?name=tom&age=15, 返回的结果如下所示:

{"protocol":null,"slashes":null,"auth":null,"host":null,"port":null,"hostname":null,"hash":null,"search":"?name=tom&age=15","query":"name=tom&age=15","pathname":"/user","path":"/user?name=tom&age=15","href":"/user?name=tom&age=15"
}

其中,queryGET 请求的参数,因为 GET 请求是没有请求体的,参数都是拼接在 url 后面的:

const http = require('http');
const url = require('url');http.createServer((req, res) => {res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});let queryObj = url.parse(req.url, true).query;res.end(JSON.stringify(queryObj));
}).listen(3000);

在浏览器中打开:http://localhost:3000/user?name=tom&age=15, 返回的结果如下所示:

{"name":"tom","age":"15"}

2.4.2 获取 POST 请求的内容

POST 请求的内容全部的都在请求体中,http.ServerRequest 并没有一个属性内容为请求体,原因是等待请求体传输可能是一件耗时的工作。

比如上传文件,而很多时候我们可能并不需要理会请求体的内容,恶意的 POST 请求会大大消耗服务器的资源,所以 node.js 默认是不会解析请求体的,当你需要的时候,需要手动来做。

const http = require('http');http.createServer(function (request, response) {var body = [];request.on('data', function (chunk) {body.push(chunk);});request.on('end', function () {body = Buffer.concat(body);console.log(body.toString());});
}).listen(80);

3、http 客户端

http 模块提供了 http.request()http.get() 两个方法,功能是作为客户端向 http 服务器发起请求。

3.1 http.request()

首先来看 http.request()http.request() 返回一个 http.ClientRequest 类的实例。

http.request(options[, callback])

  • options 可以是一个对象、或字符串、或 URL 对象。 如果 options 是一个字符串,它会被自动使用 url.parse() 解析。 如果它是一个 URL 对象, 它会被默认转换成一个 options 对象。
  • 可选的 callback 参数会作为单次监听器被添加到 'response' 事件。

官网上面的例子:

const postData = querystring.stringify({'msg' : 'Hello World!'
});const options = {hostname: 'www.google.com',port: 80,path: '/upload',method: 'POST',headers: {'Content-Type': 'application/x-www-form-urlencoded','Content-Length': Buffer.byteLength(postData)}
};const req = http.request(options, (res) => {console.log(`状态码: ${res.statusCode}`);console.log(`响应头: ${JSON.stringify(res.headers)}`);res.setEncoding('utf8');res.on('data', (chunk) => {console.log(`响应主体: ${chunk}`);});res.on('end', () => {console.log('响应中已无数据。');});
});req.on('error', (e) => {console.error(`请求遇到问题: ${e.message}`);
});// 写入数据到请求主体
req.write(postData);
req.end();

注意,在例子中调用了 req.end()使用 http.request() 必须总是调用 req.end() 来表明请求的结束,即使没有数据被写入请求主体。

3.2 http.get()

http.get(options[, callback])

http.get() 方法是 http.request() 方法的便捷方法。因为大多数请求都是 GET 请求且不带请求主体,所以 Node.js 提供了该便捷方法。

该方法与 http.request() 唯一的区别是它设置请求方法为 GET 且自动调用 req.end()

http.get('http://nodejs.org/dist/index.json', (res) => {const { statusCode } = res;const contentType = res.headers['content-type'];let error;if (statusCode !== 200) {error = new Error('请求失败。\n' + `状态码: ${statusCode}`);} else if (!/^application\/json/.test(contentType)) {error = new Error('无效的 content-type.\n' + `期望 application/json 但获取的是 ${contentType}`);}if (error) {console.error(error.message);// 消耗响应数据以释放内存res.resume();return;}res.setEncoding('utf8');let rawData = '';res.on('data', (chunk) => { rawData += chunk; });res.on('end', () => {try {const parsedData = JSON.parse(rawData);console.log(parsedData);} catch (e) {console.error(e.message);}});
}).on('error', (e) => {console.error(`错误: ${e.message}`);
});

其实 http 服务端和 http 客户端均有很多事件,但是因为太杂,就不展开去说了。对于 http 服务端,最重要的事件就是 request 事件,对于 http 客户端,最重要的事件是 response 事件。

参考资料

  • Node.js 官网文档:http 模块
  • nodejs-learning-guide:http 模块
  • 七天学会NodeJS:网络操作
  • 菜鸟教程:node.js GET/POST 请求

Node-内置模块:http相关推荐

  1. 关于Vite 客户端代码不支持node内置模块path的处理

    关于Vite 客户端不支持node内置模块path的处理 js客户端代码使用了path模块 解决方案 其他 js客户端代码使用了path模块 import 'path' from 'path' ... ...

  2. node内置模块中fs文件系统模块

    fs模块是Node.js官方提供的,用来操作文件的模块.它提高了一系列的方法和属性,用来满足用户对文件的操作需求.fs模块中,所有的方法分为同步和异步两种实现.有 sync 后缀的方法为同步方法,没有 ...

  3. node内置模块——Buffer模块(缓冲区)

    文章目录 Buffer(缓冲区) 创建Buffer 利用字符串创建buffer:Buffer.from 使用Buffer方法创建buffer:Buffer.alloc() Buffer.allocUn ...

  4. 生成html_HTML页面生成器:使用JavaScript和Node创建CLI

    在第 42 期的文章:从零开始使用JavaScript制作自己的命令行(CLI工具) 中我们介绍如何从零开始制作CLI,算是一个入门前传,知道了怎么制作CLI后今天更进一步. 在这篇文章中,我们将构建 ...

  5. php中nodethirtythree,node常用模块 - LinearLaw的个人空间 - OSCHINA - 中文开源技术交流社区...

    nodeJS和ES6 node基本用法 (1)安装nodeJS cmd输入node -v出现node版本号,表明安装成功. (2)node中的互相调用 require("./02.js&qu ...

  6. Node — 第一天

    Node-01 会 JavaScript,就能学会 Node.js!!! **Node.js 的官网地址: ** Node.js 的学习路径: JavaScript 基础语法 + Node.js 内置 ...

  7. Node.js:模块查找,引用及缓存机制

    1. Node.js的模块载入方式与机制 Node.js中模块可以通过文件路径或名字获取模块的引用.模块的引用会映射到一个js文件路径,除非它是一个Node内置模块.Node的内置模块公开了一些常用的 ...

  8. Node.js 沙箱易受原型污染攻击

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 研究人员表示,用于测试不可信 JavaScript 代码的沙箱 vm2 中存在一个漏洞,可使恶意人员规避该库的安全控制并执行远程代码执行攻击. ...

  9. 【Node.js】前端页面仔的必修课,认识node

    文章目录 前言 概念 node是个基于v8引擎的js运行环境 node使用了一个事件驱动,非阻塞式I/O的模型 node环境系统架构 应用场景 优点 前言 部分知识点来源:极客时间相关node课程,然 ...

  10. Node.js 动手实现简单的模板引擎(列表渲染)

    准备HTML模板文件index.html <!DOCTYPE html> <html lang="en"> <head><meta cha ...

最新文章

  1. 正则表达式匹配分组(|、(ab)、\num、(?P<name>)(?P=name))
  2. String 中的hashCode方法
  3. 90%的用户都不知道手机内部功能
  4. 老年机按键串号_老人机怎么解除*号键解锁
  5. ps里面怎么插入流程图_photoshop cs6绘画带箭头简单流程图的操作步骤介绍
  6. spark.mllib:Optimizer
  7. 服务器状态down,HAProxy的状态显示DOWN
  8. python身份证号掩盖出生日期的代码_利用Python制作全国身份证号验证及查询系统!就问你吊不吊!...
  9. Windows API-GDI入门基础知识详解(1)
  10. 湖南理工学院图像处理与计算机视觉,信息与通信工程一级学科硕士研究生培养方案...
  11. yanqiyetan V1.0 存档
  12. 深度deepin安装腾达U12无线网卡驱动
  13. oppor11点击Android,OPPO R11怎么网络共享?OPPO R11三种共享网络设置教程
  14. c语言课题程序框图,C语言图形五子棋课程设计报告带流程图.docx
  15. 南大软院21天学霸养成计划—第6天
  16. 查询学生的学号、课程号和成绩,并按成绩升序排序
  17. DMA+PWM驱动彩色RGB灯
  18. jaeger,zipkin,datadog,skywalking等分布式追踪工具
  19. 【C++】使用VS2022和GCC编译Xlnt库读取EXCEL
  20. 扔硬币先手获胜概率问题

热门文章

  1. 无需TCL编程能力,STKO带你轻松玩转OpenSEES
  2. NGINX应用性能优化指南(第六部分):连接优化
  3. 三平面映射TriPlanar
  4. 51单片机按键控制数码管0~9_(51单片机)课设项目1-按键控制步进电机转向、转速、启停。...
  5. 一款基于 SpringBoot 开发 OA 系统 !
  6. 分数一定是有理数吗?
  7. Linux CPU负载性能监测
  8. 2019中兴面试经验
  9. ajaxpro 使用
  10. html 游戏 背景音乐,页游广告背景音乐大全_最新页游广告背景BGM音乐大全_快吧游戏...