【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

相关文章
|
4天前
|
Web App开发 JavaScript 前端开发
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念,包括事件驱动、单线程模型和模块系统;探讨其安装配置、核心模块使用、实战应用如搭建 Web 服务器、文件操作及实时通信;分析项目结构与开发流程,讨论其优势与挑战,并通过案例展示 Node.js 在实际项目中的应用,旨在帮助开发者更好地掌握这一强大工具。
19 1
|
23天前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
124 45
|
4天前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
18 2
|
10天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【10月更文挑战第40天】在这篇文章中,我们将一起探索Node.js的奥秘,从基础概念到实际应用,逐步揭示如何利用Node.js构建高效、可扩展的后端服务。通过实际案例分析,我们将了解Node.js在现代Web开发中的应用,以及如何克服常见的开发挑战。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的见解和实用的技巧,帮助你在Node.js的道路上更进一步。
21 4
|
14天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【10月更文挑战第36天】本文将引导您探索Node.js的世界,通过实际案例揭示其背后的原理和实践方法。从基础的安装到高级的异步处理,我们将一起构建一个简单的后端服务,并讨论如何优化性能。无论您是新手还是有经验的开发者,这篇文章都将为您提供新的视角和深入的理解。
|
19天前
|
Web App开发 存储 JavaScript
深入浅出Node.js后端开发
【10月更文挑战第31天】本文将引导你进入Node.js的奇妙世界,探索其如何革新后端开发。通过浅显易懂的语言和实际代码示例,我们将一起学习Node.js的核心概念、搭建开发环境,以及实现一个简单但完整的Web应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇通往高效后端开发的大门。
|
19天前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
33 1
|
20天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【10月更文挑战第30天】本文将通过一个Node.js的简单示例,引导你进入Node.js的世界。我们将从基础概念讲起,然后一步步深入到代码实现,最后总结Node.js在后端开发中的优势和应用场景。无论你是前端开发者还是后端新手,这篇文章都将为你打开一扇了解Node.js的大门。
40 2
|
21天前
|
XML 安全 PHP
PHP与SOAP Web服务开发:基础与进阶教程
本文介绍了PHP与SOAP Web服务的基础和进阶知识,涵盖SOAP的基本概念、PHP中的SoapServer和SoapClient类的使用方法,以及服务端和客户端的开发示例。此外,还探讨了安全性、性能优化等高级主题,帮助开发者掌握更高效的Web服务开发技巧。
|
21天前
|
缓存 负载均衡 监控
性能优化:Node.js高效服务器开发技巧与最佳实践
【10月更文挑战第29天】在Node.js服务器开发中,性能优化至关重要。本文介绍了几种高效开发的最佳实践,包括使用缓存策略、采用异步编程、实施负载均衡和性能监控。通过示例代码展示了如何实现这些技术,帮助开发者构建更快、更稳定的Node.js应用。
34 2
下一篇
无影云桌面