【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

相关文章
|
9月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
664 4
|
缓存 JavaScript 前端开发
鸿蒙5开发宝藏案例分享---Web开发优化案例分享
本文深入解读鸿蒙官方文档中的 `ArkWeb` 性能优化技巧,从预启动进程到预渲染,涵盖预下载、预连接、预取POST等八大优化策略。通过代码示例详解如何提升Web页面加载速度,助你打造流畅的HarmonyOS应用体验。内容实用,按需选用,让H5页面快到飞起!
|
JavaScript 前端开发 API
鸿蒙5开发宝藏案例分享---Web加载时延优化解析
本文深入解析了鸿蒙开发中Web加载完成时延的优化技巧,结合官方案例与实际代码,助你提升性能。核心内容包括:使用DevEco Profiler和DevTools定位瓶颈、四大优化方向(资源合并、接口预取、图片懒加载、任务拆解)及高频手段总结。同时提供性能优化黄金准则,如首屏资源控制在300KB内、关键接口响应≤200ms等,帮助开发者实现丝般流畅体验。
|
前端开发 JavaScript Shell
鸿蒙5开发宝藏案例分享---Web页面内点击响应时延分析
本文为鸿蒙开发者整理了Web性能优化的实战案例解析,结合官方文档深度扩展。内容涵盖点击响应时延核心指标(≤100ms)、性能分析工具链(如DevTools时间线、ArkUI Trace抓取)以及高频优化场景,包括递归函数优化、网络请求阻塞解决方案和setTimeout滥用问题等。同时提供进阶技巧,如首帧加速、透明动画陷阱规避及Web组件初始化加速,并通过优化前后Trace对比展示成果。最后总结了快速定位问题的方法与开发建议,助力开发者提升Web应用性能。
|
JSON 开发框架 自然语言处理
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(三)
本文主要介绍了应用开发中的三大核心内容:生命周期管理、资源限定与访问以及多语言支持。在生命周期部分,详细说明了应用和页面的生命周期函数及其触发时机,帮助开发者更好地掌控应用状态变化。资源限定与访问章节,则聚焦于资源限定词的定义、命名规则及匹配逻辑,并阐述了如何通过 `$r` 引用 JS 模块内的资源。最后,多语言支持部分讲解了如何通过 JSON 文件定义多语言资源,使用 `$t` 和 `$tc` 方法实现简单格式化与单复数格式化,为全球化应用提供便利。
394 104
|
JavaScript 前端开发 API
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(二)
本文介绍了HarmonyOS应用开发中的HML、CSS和JS语法。HML作为标记语言,支持数据绑定、事件处理、列表渲染等功能;CSS用于样式定义,涵盖尺寸单位、样式导入、选择器及伪类等特性;JS实现业务逻辑,包括ES6语法支持、对象属性、数据方法及事件处理。通过具体代码示例,详细解析了页面构建与交互的实现方式,为开发者提供全面的技术指导。
475 104
|
开发框架 编解码 JavaScript
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(一)
该文档详细介绍了一个兼容JS的类Web开发范式的方舟开发框架,涵盖概述、文件组织、js标签配置及app.js等内容。框架采用HML、CSS、JavaScript三段式开发方式,支持单向数据绑定,适合中小型应用开发。文件组织部分说明了目录结构、访问规则和媒体文件格式;js标签配置包括实例名称、页面路由和窗口样式信息;app.js则描述了应用生命周期与对象管理。整体内容旨在帮助开发者快速构建基于方舟框架的应用程序。
460 102
|
10月前
|
存储 安全 前端开发
Web渗透-文件上传漏洞-上篇
文件上传漏洞常见于Web应用,因类型限制不严可致恶意文件执行。本文介绍前端检测、MIME类型、黑名单、.htaccess、空格、双写等多种绕过方式,并结合upload-labs靶场演示利用方法,提升安全防护认知。
3107 1
Web渗透-文件上传漏洞-上篇
|
10月前
|
安全 中间件 应用服务中间件
WEB渗透-文件上传漏洞-下篇
本文详解文件上传安全漏洞,涵盖白名单绕过(如00截断、条件竞争)、图片木马制作与利用、以及IIS、Apache、Nginx等常见解析漏洞原理与防御。结合实战案例,深入剖析攻击手法与修复方案。
804 1
|
C# 图形学 开发者
Unity开发中使用UnityWebRequest从HTTP服务器下载资源。
总之,UnityWebRequest就是游戏开发者手中的万能钓鱼竿,既可以获取文本数据,也能钓上图片资源,甚至是那声音的涟漪。使用UnityWebRequest的时候,你需要精心准备,比如确定URL、配置请求类型和头信息;发起请求;巧妙处理钓获的数据;还需要机智面对网络波澜,处理各种可能出现的错误。按照这样的过程,数据的钓取将会是一次既轻松愉快也效率高效的编程钓鱼之旅。
772 18