Http 模块
Web 服务器
-
什么是Web服务器?
-
当应用程序(客户端)需要某一个资源时,可以向一个台服务器,通过
Http
请求获取到这个资源;提供资源的这个服务器,就是一个Web
服务器
-
-
目前有很多开源的
Web
服务器:Nginx、Apache
(静态)、Apache Tomcat
(静态、动态)、Node.js
Web 服务器初体验
// 导入 nodejs 内置的模块
const http = require("http");
// 创建服务器对象
const app = http.createServer((require, response) => {
console.log("收到请求");
response.end("hello");
});
// 监听端口
app.listen(8000, () => {
console.log("http://localhost:8000");
});
创建服务器
-
创建服务器对象,我们是通过
createServer
来完成的http.createServer
会返回服务器的对象;- 底层其实使用直接
new Server
对象。
-
那么,当然,我们也可以自己来创建这个对象:
// 导入 nodejs 内置的模块 const http = require("http"); // 创建服务器对象 const app = new http.createServer((req, res) => { console.log("收到请求"); }); // 监听端口 app.listen(8000, () => { console.log("服务器开启成功"); });
-
上面我们已经看到,创建
Server
时会传入一个回调函数,这个回调函数在被调用时会传入两个参数:req:request
请求对象,包含请求相关的信息;res:response
响应对象,包含我们要发送给客户端的信息;
监听主机和端口号
-
Server
通过listen
方法来开启服务器,并且在某一个主机和端口上监听网络请求:- 也就是当我们通过
ip:port
的方式发送到我们监听的Web
服务器上时; - 我们就可以对其进行相关的处理;
- 也就是当我们通过
-
listen
函数有三个参数: -
端口
port
: 可以不传, 系统会默认分配端口(通过server.address().port
), 后续项目中我们会写入到环境变量中;const http = require("http"); const app = http.createServer((req, res) => { res.end("hello"); }); // 监听端口 // 省略端口号:随机开启 0-65535之间的端口号 app.listen(() => { console.log(app.address().port); });
-
主机
host
: 通常可以传入localhost
、ip
地址127.0.0.1
、或者ip
地址0.0.0.0
,默认是0.0.0.0
;-
localhost
:本质上是一个域名,通常情况下会被解析成127.0.0.1
;// 导入nodejs内置模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { res.end("hello world"); }); app.listen(8000, "localhost", () => { console.log("服务器开启成功"); });
-
127.0.0.1
:回环地址(Loop Back Address
),表达的意思其实是我们主机自己发出去的包,直接被自己接收;-
正常的数据库包经常 应用层 - 传输层 - 网络层 - 数据链路层 - 物理层 ;
-
而回环地址,是在网络层直接就被获取到了,是不会经过数据链路层和物理层的;
-
比如我们监听
127.0.0.1
时,在同一个网段下的主机中,通过ip
地址是不能访问的;// 导入nodejs内置模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { res.end("hello world"); }); app.listen(8000, "127.0.0.1", () => { console.log("服务器开启成功"); });
-
注意这里通过浏览器
127.0.0.1:8000
或者localhost:8000
都是可以访问的,但是ip
地址是不可以的
-
-
0.0.0.0:
-
监听
IPV4
上所有的地址,再根据端口找到不同的应用程序; -
比如我们监听
0.0.0.0
时,在同一个网段下的主机中,通过ip
地址是可以访问的;// 导入nodejs内置模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { res.end("hello world"); }); app.listen(8000, "0.0.0.0", () => { console.log("服务器开启成功"); });
-
这里是可以通过自己电脑的
ip
地址访问的(查询自己的ip
地址,cmd
输入ipconfig
) -
浏览器访问结果展示(以下这三个都是可以访问的)
-
-
什么也不写
// 导入nodejs内置模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { res.end("hello world"); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
首先通过本机
ip
地址访问 -
因此可以看出我们平常省略不写,省略默认的是
0.0.0.0
-
-
还有就是本机
ip
地址// 导入nodejs内置模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { res.end("hello world"); }); app.listen(8000, "192.168.0.100", () => { console.log("服务器开启成功"); });
-
这种情况就只能本地
ip
地址访问
-
-
-
回调函数:服务器启动成功时的回调函数;
request 对象
-
在向服务器发送请求时,我们会携带很多信息,比如:
-
本次请求的
URL
,服务器需要根据不同的URL
进行不同的处理; -
本次请求的请求方式,比如
GET
、POST
请求传入的参数和处理的方式是不同的; -
本次请求的
headers
中也会携带一些信息,比如客户端信息、接受数据的格式、支持的编码格式等; -
等等
const http = require("http"); const app = http.createServer((req, res) => { // 请求地址 console.log(req.url); // 请求方式 console.log(req.method); // 请求头 console.log(req.headers); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
发送请求打印结果展示
-
-
这些信息,
Node
会帮助我们封装到一个request
的对象中,我们可以直接来处理这个request
对象:
url
-
代码实例
const http = require("http"); const app = http.createServer((req, res) => { // 请求地址 console.log(req.url); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
根据上面的代码展示我们可知道请求路径是
/
-
但是如果我们给请求路径改成这样的
-
这个时候
console.log(req.url)
打印出来的结果是 -
所以我们就可以通过
url
来判断操作const http = require("http"); const app = http.createServer((req, res) => { // 请求地址 // console.log(req.url); if (req.url === "/user") { console.log("查询用户"); } else if (req.url === "/del") { console.log("删除用户"); } }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
比如:
-
输出打印结果
url 的处理
-
代码实例
const http = require("http"); const app = http.createServer((req, res) => { console.log(req.url); if (req.url === "/user") { console.log("查询用户"); } }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
当我们给
url
带一些参数的时候(这里换成了Postman接口测试工具:https://blog.csdn.net/HTML_Z/article/details/125140256
) -
发送请求,这个时候你就会发现
console.log("查询用户")
打印不出来了,路径不匹配了
URL的解析
-
我们如何对它进行解析呢?使用内置模块
url
:const http = require("http"); const url = require("url"); const app = http.createServer((req, res) => { // console.log(req.url); const obj = url.parse(req.url); console.log(obj); // if (req.url === "/user") { // console.log("查询用户"); // } }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
打印结果展示
-
这个时候我们就可以结构
obj
在进行判断const http = require("http"); const url = require("url"); const app = http.createServer((req, res) => { const { pathname } = url.parse(req.url); if (pathname === "/user") { console.log("查询用户"); } }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
发送请求,结果验证
-
这个问题解决了,但是我们打印出来的的参数
query
如何使用呢-
这里我们需要引入一个内置模块
querystring
const http = require("http"); const url = require("url"); const qs = require("querystring"); const app = http.createServer((req, res) => { const { pathname, query } = url.parse(req.url); const obj = qs.parse(query); if (pathname === "/user") { console.log("查询用户"); console.log(obj); } }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
打印结果展示
-
method的处理
-
在
Restful
规范(设计风格)中,我们对于数据的增删改查应该通过不同的请求方式:-
GET
:查询数据; -
POST
:新建数据; -
PATCH
:更新数据; -
DELETE
:删除数据;const http = require("http"); const app = http.createServer((req, res) => { if (req.method === "GET") { console.log("查询"); } else if (req.method == "POST") { console.log("修改"); } else if (req.method == "DELETE") { console.log("删除"); } else if (req.method == "PUT") { console.log("新增"); } }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
-
所以,我们可以通过判断不同的请求方式进行不同的处理。
- 比如创建一个用户:
- 请求接口为
/users
; - 请求方式为
POST
请求; - 携带数据
username
和password
;
创建用户接口
-
在我们程序中如何进行判断以及获取对应的数据呢?
-
这里我们需要判断接口是
/users
,并且请求方式是POST
方法去获取传入的数据; -
获取这种
body
携带的数据,我们需要通过监听req
的data
事件来获取; -
代码实例展示
const http = require("http"); const app = http.createServer((req, res) => { if (req.method === "POST") { // 获取参数 req.on("data", (data) => { console.log(data); }); } }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
发送请求打印结果(Buffer类型)
-
-
将
JSON
字符串格式转成对象类型,通过JSON.parse
方法即可。const http = require("http"); const app = http.createServer((req, res) => { if (req.method === "POST") { let buffer = ""; let obj = {}; req.on("data", (data) => { buffer += data; }); req.on("end", () => { const str = buffer.toString(); obj = JSON.parse(str); console.log(obj); }); } }); app.listen(8000, () => { console.log("服务器开启成功"); });
const http = require("http"); const app = http.createServer((req, res) => { if (req.method === "POST") { let buffer = ""; // 设置字符集 utf8 req.setEncoding = "utf8"; req.on("data", (data) => { buffer += data; }); req.on("end", () => { console.log(JSON.parse(buffer)); }); } }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
发送请求,结果显示
-
headers属性
-
在
request
对象的header
中也包含很多有用的信息,客户端会默认传递过来一些信息:const http = require("http"); const app = http.createServer((req, res) => { console.log(req.headers); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
控制台打印结果
-
-
content-type
是这次请求携带的数据的类型:-
application/json
表示是一个json
类型; -
text/plain
表示是文本类型; -
application/xml
表示是xml
类型; -
multipart/form-data
表示是上传文件; -
x-www-form-urlencoded
表单数据,不能上传文件const http = require("http"); const app = http.createServer((req, res) => { console.log(req.headers["content-type"]); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
-
content-length
:文件的大小和长度 -
keep-alive
:(保持会话的时间)http
是基于TCP
协议的,但是通常在进行一次请求和响应结束后会立刻中断;- 在
http1.0
中,如果想要继续保持连接:- 浏览器需要在请求头中添加
connection: keep-alive
; - 服务器需要在响应头中添加
connection:keey-alive
; - 当客户端再次放请求时,就会使用同一个连接,直接一方中断连接;
- 浏览器需要在请求头中添加
- 在
http1.1
中,所有连接默认是connection: keep-alive
的;- 不同的
Web
服务器会有不同的保持keep-alive
的时间; Node
中默认是5s
中;
- 不同的
-
accept-encoding
:告知服务器,客户端支持的文件压缩格式,比如js
文件可以使用gzip
编码,对应.gz
文件; -
accept
:告知服务器,客户端可接受文件的格式类型; -
user-agent
:客户端相关的信息;
返回响应结果
-
如果我们希望给客户端响应的结果数据,可以通过两种方式:
-
Write
方法:这种方式是直接写出数据,但是并没有关闭流;const http = require("http"); const app = http.createServer((req, res) => { // 响应方式一 res.write("你好"); // 结束会话 完整的请求 res.end("在干吗"); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
end
方法:这种方式是写出最后的数据,并且写出后会关闭流;const http = require("http"); const app = http.createServer((req, res) => { // 响应方式二 res.end("hello"); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
上面我们响应的是一个字符串,那假如是对象或者数组呢?
-
对象
const http = require("http"); const app = http.createServer((req, res) => { const user = { id: 1, username: "张三", age: 20, }; res.end(JSON.stringify(user)); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
数组
const http = require("http"); const app = http.createServer((req, res) => { const users = [ { id: 1, username: "张三", age: 20, }, { id: 2, username: "李四", age: 18, }, ]; res.end(JSON.stringify(users)); }); app.listen(8000, () => { console.log("服务器开启成功"); });
-
-
-
如果我们没有调用
end
和close
,客户端将会一直等待结果:\- 所以客户端在发送网络请求时,都会设置超时时间。
返回状态码
-
Http
状态码(Http Status Code
)是用来表示Http
响应状态的数字代码:-
Http
状态码非常多,可以根据不同的情况,给客户端返回不同的状态码; -
常见的状态码是下面这些(后续项目中,也会用到其中的状态码);
状态代码 状态描述 说明 200 OK 客户端请求成功 400 Bad Request 由于客户端请求 有语法错误,不能被服务器所理解 401 Unauthorized 请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用 403 Forbidden 服务器收到请求,但是拒绝提供服务,服务器通常会在响应正文中给出不提供服务的原因 404 Not Found 请求的资源不存在,例如:输入了错误的URL 500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求 503 Service Unavaliable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常
-
-
设置状态码常见的有两种方式:
-
第一种
// 导入 nodejs 内置的模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { // 响应状态码设置 res.statusCode = 400; res.end("123"); }); // 监听端口 app.listen(8000, () => { console.log("http://localhost:8000"); });
-
第二种
// 导入 nodejs 内置的模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { // 响应状态码设置 res.writeHead(400); res.end("123"); }); // 监听端口 app.listen(8000, () => { console.log("http://localhost:8000"); });
-
响应头文件
-
返回头部信息,主要有两种方式:
-
res.setHeader
:一次写入一个头部信息;// 导入 nodejs 内置的模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { res.setHeader("content-type", "application/json;charset=utf8"); const user = { id: 1, name: "admin", nickName: "张三", }; res.end(JSON.stringify(user)); }); // 监听端口 app.listen(8000, () => { console.log("http://localhost:8000"); });
-
res.writeHead
:同时写入header
和status
;// 导入 nodejs 内置的模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { res.writeHead(200, { "content-type": "text/html", }); const user = { id: 1, name: "admin", nickName: "张三", }; res.end("<h2>hello world</h2>"); }); // 监听端口 app.listen(8000, () => { console.log("http://localhost:8000"); });
-
-
Header
设置Content-Type
有什么作用呢?- 默认客户端接收到的是字符串,客户端会按照自己默认的方式进行处理;
http 请求
-
axios
库可以在浏览器中使用,也可以在Node中使用:-
在浏览器中,
axios
使用的是封装xhr
; -
在
Node
中,使用的是http
内置模块;// 导入 nodejs 内置的模块 const http = require("http"); // 创建服务器对象 const app = http.createServer((req, res) => { const user = [ { id: 1, username: "admin", nickname: "张三", gender: 1, }, { id: 2, username: "admin", nickname: "王五", gender: 1, }, { id: 3, username: "admin", nickname: "李四", gender: 0, }, { id: 4, username: "admin", nickname: "大大", gender: 1, }, ]; res.end(JSON.stringify(user)); }); // 监听端口 app.listen(8000, () => { console.log("http://localhost:8000"); });
const http = require("http"); const app = http.createServer((req, res) => { // http.get("http://localhost:8000", (res) => { // res.on("data", (data) => { // console.log(data.toString()); // console.log(JSON.parse(data.toString())); // }); // }); http .request( { hostname: "localhost", port: 8000, method: "POST", }, (res) => { res.on("data", (data) => { console.log(JSON.parse(data.toString())); }); } ) .end(); res.end(); }); app.listen(9999, () => { console.log("9999开启成功"); });
-
终端打印结果
-
-