Create a HTTP Server by Nodejs

Quick Start

配置环境和依赖

  1. 下载安装Nodejs
    • $node -v 查看是否已经安装
    • nodejs安装完自带npm(Nodejs平台的默认包管理工具)
  2. 安装 Yarn
    # 通过 npm 可以全局或本地安装依赖包,当本地安装时 npm 会根据 package.json 安装最新的依赖包,同时自动生成并更新 package-lock.json 文件,这就引发了一个问题:如果一个依赖包在 package.json 标记版本范围内发布了有问题的新版本,那么我们自己的项目也会跟着出问题。
    # 相比 npm,yarn 会严格按照自动生成的 yarn.lock 本地安装依赖包,只有增删依赖或者 package.json 标记版本发生不可兼容的变化时才会更新 yarn.lock,这就彻底杜绝了上述 npm 的问题。考虑到企业级 Web 服务器对稳定性的要求,yarn 是必要的。
    $npm i -g yarn
  3. 下载第三方模块
    # 新建一个文件夹,并在当前文件夹内创建一个js文件,比如app.js
    $npm init # 安装package.json文件
    $npm install express --save # 安装express库
  4. 安装Docker
    做一个 Web 服务器会有两种部署选择,要么是传统的包部署,要么是容器镜像部署
    后者较前者在编排上更方便,结合 Kubernetes 可以做到很好的伸缩,是当前发展的趋势

创建一个静态资源服务器

初始化工程

准备好了环境就可以开始编码了,先新建工程根目录,然后进入并初始化package.json与目录结构

$ mkdir node        # 新建工程根目录
$ cd node           # 进入工程根目录

$ yarn init -y      # 初始化 package.json
yarn init v1.22.4
success Saved package.json

$ mkdir src         # 新建 src 目录存放核心逻辑
$ mkdir public      # 新建 public 目录存放静态资源

$ tree -L 1         # 展示当前目录内容结构
.
├── package.json
├── public
└── src

Express

Express是Node.js服务端基础框架。发布于2010年,凭借出色的中间件机制在开源社区积累了大量的成熟模块,现在是OpenJS基金会At-Large级别项目。Express模块的贡献者热心于维护与更新,在全面的考量下Express是更稳健的选择。
几个常用模块:

模块名称 功能简介 Star Contributers Used by 最近提交时间
passport 认证登录 17.7k 33 385k 2020-06-10
connect-redis 会话存储 2.3k 51 26.3k 2020-07-10
helmet 网络安全 7.2k 25 136.4k 2020-07-11

在工程根目录执行以下命令安装Express

$ yarn add express  # 本地安装 Express
# ...
info Direct dependencies
└─ express@4.17.1
# ...

$ tree -L 1         # 展示当前目录内容结构
.
├── node_modules
├── package.json
├── public
├── src
└── yarn.lock

静态服务

现在可以开始写应用逻辑了,先做一个静态资源服务器,以public目录为静态资源目录:

// src/server.js
const express = require('express');
const { resolve } = require('path');
const { promisify } = require('util');

const server = express();
const port = parseInt(process.env.PORT || '9000');
const publicDir = resolve('public');

async function bootstrap() {
  server.use(express.static(publicDir));
  await promisify(server.listen.bind(server, port))();
  console.log(`> Started on port ${port}`);
}

bootstrap();
<!-- public/index.html -->
<html>
  <head>
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>It works!</h1>
  </body>
</html>
$ tree -L 2 -I node_modules   # 展示除了node_modules之外的目录内容结构
.
├── package.json
├── public
│   └── index.html
├── src
│   └── server.js
└── yarn.lock

逻辑写好之后在package.json中设置启动脚本:

{
  "name": "00-static",
  "version": "1.0.0",
-  "main": "index.js",
+  "scripts": {
+    "start": "node src/server.js"
+  },
  "license": "MIT",
  "dependencies": {
    "express": "^4.17.1"
  }
}

refer

//1. 加载http模块
var http = require('http');

//2. 创建http服务器
// 参数: 请求的回调, 当有人访问服务器的时候,就会自动调用回调函数
var server = http.createServer(function (request, response) {
    console.log('有人访问了服务器')

    //回调数据
    response.write('Hello, My Love')
    response.end()
})

//3. 绑定端口
server.listen(3000, '127.0.0.1')

//4. 执行
console.log('执行了3000')

// http://localhost:5000
$node app.js # 运行服务器

Create Server by Express

Use Express Framework

1. 引入express模块
2. 创建express服务器
3. get, post请求中:
    - 参数一: 请求根路径
        - 若传'/', 则url为: http://192.168.0.0:3030
        - 若传'/home', 则url为: http://192.168.0.0:3030/home
    - 参数二: 请求数据的回调函数
4. 监听端口: 默认url为当前电脑的IP地址
/* express的服务器 */

//1. 导入express
var express = require('express')

//2. 创建express服务器
var server = express()

//3. 访问服务器(get或者post)
//参数一: 请求根路径
//3.1 get请求
server.get('/', function (request, response) {
    // console.log(request)
    response.send('get请求成功')
})

//3.2 post请求
server.post('/', function (request, response) {
    response.send('post请求成功')
})

//4. 绑定端口
server.listen(5000)
console.log('启动5000')

// http://localhost:5000

路由

1. 路由: 针对不同的URL有不同的处理方式
2. 添加url路径: 根据不同路径,显示不同内容
3. 路由句柄(索引): 执行完一个函数,再执行下一个,因为有时候处理一个请求,需要做很多其他事情,写在一起业务逻辑不好分开
4. 函数一定要添加next参数,一定要调用next(),才会进行下面操作,代码使一行一行执行
//3.1 get请求
server.get('/', function (request, response, next) {
    // console.log(request)
    console.log('从据库获取数据') // 显示在terminal里
    next()
}, function (request, response) {
    response.send('get请求成功') // 显示在网页上
})

// http://localhost:5000

中间件

- 优化代码,使代码清晰可读
- 原理: 发送一个请求给服务器的时候,会被中间件拦截,先由中间件处理,每个中间件都有一个回调函数作为参数,拦截到参数,就会自动执行回调函数。
- 注意:有中间件use,会先执行中间件的回调函数,然后才会调用get或者post的回调函数,也就是当监听到请求,先执行中间件,才会到get、post请求。
- use是express注册中间件的方法
//3. 创建中间件:use
//截取请求, 拦截回调
server.use('/', function (request, response, next) {
    console.log('执行中间件')
    // console.log('获取数据库数据')
    console.log(request.query.page)
    next()
})

//4. 访问服务器(get或者post)
//参数一: 请求根路径
//4.1 get请求
server.get('/home', function (request, response) {
    // console.log(request)
    response.send('get参数请求成功')
})

// http://localhost:5000/home

get请求参数

- request.query会把请求参数包装成字典对象,直接通过点就能获取参数
//4. 访问服务器(get或者post)
//参数一: 请求根路径
//4.1 get请求
server.get('/home', function (request, response) {
    // console.log(request)
    console.log(request.query.page) // 12
    response.send('get参数请求成功')
})

// http://localhost:5000/home?page=12

post请求参数

先看一下request的部分参数

headers: 
   { 
   //请求头
     host: 'http://localhost:5000/home',
     //保持长连接
     connection: 'keep-alive',
     'cache-control': 'max-age=0',
     'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36',
     'upgrade-insecure-requests': '1',
     //可接受的数据解析方式
     accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
     'accept-encoding': 'gzip, deflate',
     'accept-language': 'zh-CN,zh;q=0.9',
     'if-none-match': 'W/"15-H7HlVCzzVfmRL56LAnLfNUaMM+8"' 
   }
- 使用http发送请求,需要设置content-type字段
- content-type字段
    - application/x-www-form-urlencoded(普通请求,默认一般使用这种)
    - application/json(带有json格式的参数,需要使用这个,比如参数是字典或者数组)
    - multipart/form-data(传输文件,文件上传使用这个)
- Node.js需要使用body-parser模块,解析post请求参数
- 可以采用中间件的方式解析post请求参数
    - 注意bodyParser.urlencoded参数是一个字典,需要添加{}包装
    - extends必传参数,是否展开
Author: ElaineXHZhong
Link: https://elainexhzhong.github.io/2021/06/03/Create-a-HTTP-Server-by-Nodejs/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.