【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

相关文章
|
3月前
|
C# 图形学 开发者
Unity开发中使用UnityWebRequest从HTTP服务器下载资源。
总之,UnityWebRequest就是游戏开发者手中的万能钓鱼竿,既可以获取文本数据,也能钓上图片资源,甚至是那声音的涟漪。使用UnityWebRequest的时候,你需要精心准备,比如确定URL、配置请求类型和头信息;发起请求;巧妙处理钓获的数据;还需要机智面对网络波澜,处理各种可能出现的错误。按照这样的过程,数据的钓取将会是一次既轻松愉快也效率高效的编程钓鱼之旅。
201 18
|
4月前
|
Web App开发 前端开发 JavaScript
鸿蒙5开发宝藏案例分享---Web适配一多开发实践
这是一份实用的鸿蒙Web多设备适配开发指南,针对开发者在不同屏幕尺寸下的布局难题提供了解决方案。文章通过三大法宝(相对单位、媒体查询和窗口监听)详细介绍如何实现智能适配,并提供了多个实战案例,如宫格布局、对话框变形和自适应轮播图等。此外,还分享了调试技巧及工具推荐,帮助开发者快速上手并优化性能。最后鼓励读者实践探索,并提示更多官方资源等待发现。
|
6月前
|
关系型数据库 MySQL 数据库
基于Flink CDC 开发,支持Web-UI的实时KingBase 连接器,三大模式无缝切换,效率翻倍!
TIS 是一款基于Web-UI的开源大数据集成工具,通过与人大金仓Kingbase的深度整合,提供高效、灵活的实时数据集成方案。它支持增量数据监听和实时写入,兼容MySQL、PostgreSQL和Oracle模式,无需编写复杂脚本,操作简单直观,特别适合非专业开发人员使用。TIS率先实现了Kingbase CDC连接器的整合,成为业界首个开箱即用的Kingbase CDC数据同步解决方案,助力企业数字化转型。
1197 5
基于Flink CDC 开发,支持Web-UI的实时KingBase 连接器,三大模式无缝切换,效率翻倍!
|
6月前
|
Kubernetes API 网络安全
当node节点kubectl 命令无法连接到 Kubernetes API 服务器
当Node节点上的 `kubectl`无法连接到Kubernetes API服务器时,可以通过以上步骤逐步排查和解决问题。首先确保网络连接正常,验证 `kubeconfig`文件配置正确,检查API服务器和Node节点的状态,最后排除防火墙或网络策略的干扰,并通过重启服务恢复正常连接。通过这些措施,可以有效解决与Kubernetes API服务器通信的常见问题,从而保障集群的正常运行。
429 17
|
5月前
|
Go API 定位技术
MCP 实战:用 Go 语言开发一个查询 IP 信息的 MCP 服务器
随着 MCP 的快速普及和广泛应用,MCP 服务器也层出不穷。大多数开发者使用的 MCP 服务器开发库是官方提供的 typescript-sdk,而作为 Go 开发者,我们也可以借助优秀的第三方库去开发 MCP 服务器,例如 ThinkInAIXYZ/go-mcp。 本文将详细介绍如何在 Go 语言中使用 go-mcp 库来开发一个查询 IP 信息的 MCP 服务器。
358 0
|
6月前
|
机器学习/深度学习 开发框架 API
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。
|
8月前
|
监控 前端开发 应用服务中间件
小游戏源码开发搭建技术栈和服务器配置流程
近些年不同场景游戏层出不穷,现就小游戏开发技术应用及功能详细剖析!
|
9月前
|
存储 人工智能 自然语言处理
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
ChatMCP 是一款基于模型上下文协议(MCP)的 AI 聊天客户端,支持多语言和自动化安装。它能够与多种大型语言模型(LLM)如 OpenAI、Claude 和 OLLama 等进行交互,具备自动化安装 MCP 服务器、SSE 传输支持、自动选择服务器、聊天记录管理等功能。
2353 16
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
|
9月前
|
前端开发 安全 JavaScript
2025年,Web3开发学习路线全指南
本文提供了一条针对Dapp应用开发的学习路线,涵盖了Web3领域的重要技术栈,如区块链基础、以太坊技术、Solidity编程、智能合约开发及安全、web3.js和ethers.js库的使用、Truffle框架等。文章首先分析了国内区块链企业的技术需求,随后详细介绍了每个技术点的学习资源和方法,旨在帮助初学者系统地掌握Dapp开发所需的知识和技能。
2025年,Web3开发学习路线全指南