2023-02-24
Nodejs
00

目录

1. 创建服务器
2. Request 请求
2.1 Request 对象
2.2 URL 的处理
2.3 URL 的解析
2.4 请求头
3. Response 响应
3.1 返回响应结果
3.2 返回状态码
3.3 响应头文件
4. 文件上传

1. 创建服务器

什么是 Web 服务器?

  • 当应用程序(客户端)需要某个资源时,可以向一台服务器,通过 HTTP 请求获取到这个资源
  • 提供资源的这个服务器,就是一个 Web 服务器

image.png

目前有很多开源的 Web 服务器:NginxApache(静态)Apache Tomcat(静态、动态)Node.js

Node 中,提供 web 服务器的资源返回给浏览器,主要是通过 http 模块。

我们先简单对它做一个使用:

js
const http = require("http"); const HTTP_PORT = 9000; const server = http.createServer((req, res) => { res.end("Hello World"); }); server.listen(HTTP_PORT, () => { console.log(`服务器在${HTTP_PORT}启动`); });

此时我们在浏览器中输入 localhost:9000,就会出现 Hello World

image.png

解释上面这段代码:

  1. 通过 http 模块的 createServer 方法创建了一个服务器对象,它的底层其实是直接使用 new Server 创建对象的。

    image.png

    那么当然,我们也可以自己来创建这个对象:

    js
    const server = new http.Server((req, res) => { res.end("Hello World"); }); server.listen(HTTP_PORT, () => { console.log(`服务器在${HTTP_PORT}启动`); });
  2. 创建 Server 时会传入一个回调函数,这个回调函数在被调用时会传入两个参数:

    1. reqrequest 请求对象,包含请求相关的信息;
    2. resresponse 响应对象,包含我们要发送给客户端的信息;
  3. Server 通过 listen 方法来开启服务器,并且在某一个主机的端口上监听网络请求

    也就是当我们通过 ip:port 的方式发送到我们监听的 Web 服务器上时,我们就可以对其进行相关的处理;

    listen 函数有三个参数:

    1. 端口 port:可以不传,系统会默认分配端

    2. 主机 host:通常可以传入 localhostip地址127.0.0.1、或者 ip地址0.0.0.0,默认是 0.0.0.0

      1. localhost:本质上是一个域名,通常情况下会被解析成 127.0.0.1

      2. 127.0.0.1回环地址(Loop Back Address),表达的意思其实是我们主机自己发出去的包,直接被自己接收;

        • 正常的数据包会经过 应用层 - 传输层 - 网络层 - 数据链路层 - 物理层
        • 而回环地址,是在网络层直接就被获取到了,是不会经常数据链路层物理层的;
        • 比如我们监听 127.0.0.1 时,在同一个网段下的主机中,通过 ip地址 是不能访问的;
      3. 0.0.0.0

        • 监听 IPV4 上所有的地址,再根据端口找到不同的应用程序;
        • 比如我们监听 0.0.0.0 时,在同一个网段下的主机中,通过 ip 地址是可以访问的;
    3. 回调函数:服务器启动成功时的回调函数;

2. Request 请求

2.1 Request 对象

在向服务器发送请求时,我们会携带很多信息,比如:

  1. 本次请求的 URL,服务器需要根据不同的 URL 进行不同的处理;
  2. 本次请求的请求方式,比如 GETPOST 请求传入的参数和处理的方式是不同的;
  3. 本次请求的 headers 中也会携带一些信息,比如客户端信息接收数据的格式支持的编码格式等;
  4. 等等...

这些信息,Node 会帮助我们封装到一个 request 的对象中,我们可以直接来处理这个 request 对象:

js
const server = new http.Server((req, res) => { // request 对象 console.log(req) console.log(req.method) console.log(req.headers) res.end("Hello World"); });

2.2 URL 的处理

客户端在发送请求时,会请求不同的数据,那么会传入不同的请求地址:

  • 比如 http://localhost:9000/login

  • 比如 http://localhost:9000/products;

服务器端需要根据不同的请求地址,作出不同的响应:

js
const server = new http.Server((req, res) => { const url = req.url; if (url === "/login") { res.end("welcome Back~"); } else if (url === "/products") { res.end("products"); } else { res.end("error message"); } });

image.png

2.3 URL 的解析

如果用户发送的地址中还携带一些额外的参数,例如以下情况

  • http://localhost:9000/login?name=why&password=123;

  • 这个时候,url 的值是 /login?name=why&password=123

这个时候我们可以使用内置模块 url 处理

js
const parseInfo = url.parse(req.url); console.log(parseInfo)

此时的 parseInfo 为:

image.png

接下来我们就可以直接用 qs 或者 URLSearchParams 处理 query 拿到参数了

js
const queryObj = new URLSearchParams(parseInfo.query); console.log(queryObj.get("name")); console.log(queryObj.get("password"));

2.4 请求头

request 对象的 header 中也包含很多有用的信息,客户端会默认传递过来一些信息:

image.png

  1. content-type 是这次请求携带的数据的类型:
    1. application/x-www-form-urlencoded:表示数据被编码成以 '&' 分隔的键 - 值对,同时以 '=' 分隔键和值
    2. application/json:表示是一个 json 类型;
    3. text/plain:表示是文本类型
    4. application/xml:表示是 xml 类型;
    5. multipart/form-data:表示是上传文件;
  2. content-length:文件的大小长度
  3. keep-alive
    1. http 是基于 TCP 协议的,但是通常在进行一次请求和响应结束后会立刻中断;
    2. http1.0 中,如果想要继续保持连接:
      1. 浏览器需要在请求头中添加 connection: keep-alive
      2. 服务器需要在响应头中添加 connection: keep-alive
      3. 当客户端再次放请求时,就会使用同一个连接,直接一方中断连接;
    3. http1.1 中,所有连接默认是 connection: keep-alive 的;
      1. 不同的 Web 服务器会有不同的保持 keep-alive 的时间;
      2. Node 中默认是 5s 中;
  4. accept-encoding:告知服务器,客户端支持的文件压缩格式,比如 js 文件可以使用 gzip 编码,对应 .gz 文件;
  5. accept:告知服务器,客户端可接受文件的格式类型;
  6. user-agent:客户端相关的信息;

3. Response 响应

3.1 返回响应结果

如果我们希望给客户端响应的结果数据,可以通过两种方式:

  1. write方法:这种方式是直接写出数据,但是并没有关闭流
  2. end方法:这种方式是写出最后的数据,并且写出后会关闭流
js
// 响应数据的两个方式 res.write('Hello World) res.write("Hello Response") res.edn("message end")

如果我们没有调用 endclose,客户端将会一直等待结果:

  • 所以客户端在发送网络请求时,都会设置超时时间。

3.2 返回状态码

Http状态码(Http Status Code)是用来表示 Http 响应状态的数字代码:

常见HTTP状态码状态描述信息说明
200OK客户端请求成功
201CreatedPOST请求,创建新的资源
301Moved Permanently请求资源的URL已经修改,响应中会给出新的URL
400Bad Request客户端的错误,服务器无法或者不进行处理
401Unauthorized未授权的错误,必须携带请求的身份信息
403Forbidden客户端没有权限访问,被拒接
404Not Found服务器找不到请求的资源
500Internal Server Error服务器遇到了不知道如何处理的情况。
503Service Unavailable服务器不可用,可能处于维护或者重载状态,暂时无法访问
js
// 1. res.statusCode = 400 // 2. res.writeHead(200)

3.3 响应头文件

返回头部信息,主要有两种方式:

  1. res.setHeader:一次写入一个头部信息;

  2. res.writeHead:同时写入 headerstatus

js
res.setHeader('Context-Type', 'application/json;charset=utf8') res.writeHead(200, { "Content-Type": "application/json;charset=utf8" })

Header 设置 Content-Type 有什么作用呢?

  • 默认客户端接收到的是字符串,客户端会按照自己默认的方式进行处理;

image.png

4. 文件上传

其实对于后端,手动处理上传的文件是很复杂的,正常情况下我们都会借助于一些插件做处理, 下面仅做对于图片上传的一个简单的演示。

js
const http = require("http"); const qs = require("querystring"); const fs = require("fs"); const HTTP_PORT = 9000; // 1. 创建 sever 服务器 const server = new http.Server((req, res) => { // 文件设置为二进制 req.setEncoding("binary"); // 获取 content-type 中的 boundary的值 let boundary = req.headers["content-type"] .split("; ")[1] .replace("boundary=", ""); const fileSize = req.headers["content-length"]; let curSize = 0; let body = ""; req.on("data", (data) => { curSize += data.length; res.write(`文件上传进度:${(curSize / fileSize) * 100}%\n`); body += data; }); req.on("end", () => { // 切割数据 const payload = qs.parse(body, "\r\n", ":"); // 获取最后的类型(image/png) const fileType = payload["Content-Type"].substring(1); // 获取要截取的长度 const fileTypePosition = body.indexOf(fileType) + fileType.length; let binaryData = body.substring(fileTypePosition); binaryData = binaryData.replace(/^\s\s*/, ""); const finalData = binaryData.substring( 0, binaryData.indexOf("--" + boundary + "--") ); fs.writeFile("./foo.png", finalData, "binary", (err) => { console.log(err); res.end("文件上传完成~"); }); }); }); // 2. 开启 server 服务器 server.listen(HTTP_PORT, () => { console.log(`服务器在${HTTP_PORT}启动`); });

使用 postman 测试,并查看图片能显示。

image.png

image.png

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:叶继伟

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!