【Node 基础】Web服务器开发和文件上传

简介: 【Node 基础】Web服务器开发和文件上传

原文来自 我的个人博客

1. 创建服务器

什么是 Web 服务器?

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

image.png

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

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

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

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

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

    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 对象:

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;

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

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 处理

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

此时的 parseInfo 为:

image.png

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

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方法:这种方式是写出最后的数据,并且写出后会关闭流
// 响应数据的两个方式
res.write('Hello World)
res.write("Hello Response")
res.edn("message end")

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

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

3.2 返回状态码

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

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

3.3 响应头文件

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

  1. res.setHeader:一次写入一个头部信息;
  2. res.writeHead:同时写入 headerstatus
res.setHeader('Context-Type', 'application/json;charset=utf8')

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

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

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

image.png

4. 文件上传

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

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

相关文章
|
19小时前
|
设计模式 开发框架 数据库
Python Web开发主要常用的框架
Python Web开发框架包括Django、Flask、Tornado和Pyramid。Django适用于复杂应用,提供ORM、模板引擎等全套功能;Flask轻量级,易于扩展,适合小型至中型项目;Tornado擅长处理高并发,支持异步和WebSockets;Pyramid灵活强大,可适配多种数据库和模板引擎,适用于各种规模项目。选择框架需依据项目需求和技术栈。
8 2
|
19小时前
|
安全 测试技术 持续交付
在Python Web开发中,测试是一个至关重要的环节
【5月更文挑战第12天】在Python Web开发中,测试至关重要,包括单元测试(unittest模块)、集成测试、功能测试、系统测试、验收测试、性能测试、安全测试和端到端测试。常用的测试工具有unittest、pytest、selenium、requests和coverage。遵循“测试先行”和“持续集成”原则,确保代码质量与稳定性。
8 3
|
2天前
|
编解码 数据库 计算机视觉
LabVIEW开发基于Web数字图像处理
LabVIEW开发基于Web数字图像处理
|
2天前
LabVIEW使用VI服务器的调用节点将数据传递到另一个VI 使用调用节点(Invoke Node)与通过引用调用节点(Call by Reference)调用VI时有什么差别?
LabVIEW使用VI服务器的调用节点将数据传递到另一个VI 使用调用节点(Invoke Node)与通过引用调用节点(Call by Reference)调用VI时有什么差别?
|
4天前
|
前端开发 JavaScript Java
Java与Web开发的结合:JSP与Servlet
Java与Web开发的结合:JSP与Servlet
8 0
|
4天前
|
存储 程序员 API
python web开发示例详解
python web开发示例详解
13 0
|
5天前
|
XML 前端开发 JavaScript
CSR(客户端渲染)和AJAX在Web开发中各自扮演不同的角色
【5月更文挑战第8天】CSR(客户端渲染)与AJAX在Web开发中各司其职。CSR提供初始HTML框架,通过JavaScript在浏览器端获取并渲染数据,提升交互性和响应速度。AJAX则实现页面局部更新,如实时搜索,不刷新页面即可获取数据。CSR可能因DOM操作多而引发性能问题,但可优化解决;AJAX适合频繁交互场景,提高响应性。两者在不同需求下各有优势,需按项目选择适用技术。
13 4
|
5天前
|
前端开发 搜索推荐 安全
AJAX和CSR(客户端渲染)是Web开发中常用的两种技术
【5月更文挑战第8天】AJAX提升用户体验,减轻服务器压力,但对搜索引擎不友好且增加开发复杂度,易引发安全问题。CSR提供快速响应和交互性,改善用户体验,但首屏加载慢,搜索引擎支持不足,同样面临安全挑战。两者各有适用场景,需按项目需求选择。
10 0
|
6天前
|
前端开发 JavaScript 开发者
新一代前端框架:革命性的Web开发利器
传统的前端框架在满足日益复杂的Web开发需求上逐渐显露出局限性,而新一代前端框架的出现,以其革命性的设计和功能,重新定义了Web开发的标准。本文将介绍这些新一代前端框架的特点和优势,并探讨它们在实际项目中的应用。
|
7天前
|
安全 测试技术 PHP
掌握现代Web开发:PHP 8的新特性与最佳实践
【5月更文挑战第5天】 在当今快速发展的网络世界中,PHP作为一种流行的服务器端脚本语言,持续地演化着。最新的PHP 8版本引入了一系列令人兴奋的新特性和性能改进,为开发者提供了更加强大和灵活的工具。本文将深入探讨PHP 8中的新特性,包括联合类型、名称参数、匹配表达式等,并分享一些最佳实践,帮助开发者提高代码质量,优化性能,并确保安全性。通过这些实用技巧和示例,您将能够构建更高效、更安全的PHP应用程序。