• nodejs搭建服务器手册


    一 使用node.js搭建原生服务器

    使用node.js搭建原生服务器,实际是使用node中自带的http模块创建一个服务,这个服务自运行起对特定接口进行监听。

    当有对特定接口的请求时,会执行指定的回调函数,在回调函数中对请求的url进行解析,根据不同的url,执行并返回不同的结果。

    我们先建立一个js文件(这里确保已安装了node.js环境),在js文件中引入http模块(无需install直接引入即可),然后建立一个接口监听器。

    // index.js
    const http = require("http")
    
    http.createServer(function(req, res) {
        res.writeHead(200)
        res.end(req.url)
    })
    .listen(3001)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在文件所在的目录打开命令行,输入node index执行该文件,执行后命令行广播停在下一行开始的位置,代表服务器已经成功启动了。

    打开浏览器,可以在localhost:3001访问到该接口,返回的值直接打印在了页面上。

    结合上面的代码我们可以猜到,res.writeHead函数是为接口返回赋状态码,res.end决定接口给出的值,req.url是对请求url的获取。

    在上面的示例中,服务器对任意请求的返回值是相同的,就是自身的url,接下来我们需要对url进行分析,以给出更多路由对应的解决方案。

    我们可以使用node原生url模块对url进行解析,它会根据url解析出一个对象,内部包括该url的路由地址和参数。

    再使用原生模块querystring将参数解析成对象。

    首先我们引入http、url、querystring模块。

    const http = require("http")
    const url = require('url')
    const querystring = require('querystring')
    
    • 1
    • 2
    • 3

    在createServer中我们使用url模块将原始url字符串解析成对象。

    const url2 = url.parse(req.url)
    
    • 1

    这时我们可以通过url2.pathname来获取路由,通过url2.query来获取参数。

    最后通过querystring对参数解析,返回结果。

    const http = require("http")
    const url = require('url')
    const querystring = require('querystring')
    
    http.createServer(function(req, res) {
        const url2 = url.parse(req.url)
        if(url2.pathname == '/') {
            const query = querystring.parse(url2.query)
            const param = query.action
            res.writeHead(200)
            res.end(param)
        }
    })
    .listen(3001)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    通过对url的解析,现在我们可以对不同的路由执行不同的逻辑代码,并且可以获取到传入的参数了。

    http.createServer(function(req, res) {
        const url2 = url.parse(req.url)
    
        if(url2.pathname == 'favicon.ico') {
            res.writeHead(200)
            res.end('hello')
            return
        }
        if(url2.pathname == '/') {
            const query = querystring.parse(url2.query)
            const param = query.action
            res.writeHead(200)
            res.end(param)
        }
        if(url2.pathname == '/game') {
            res.writeHead(200)
            res.end('hellow game')
        }
    })
    .listen(3001)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    当前我们返回的是数据,返回html文件该如何操作呢。

    首先我们引入node模块fs,

    使用fs创建管道使对应地址的文件注入res即可,不理解没关系,看代码。

    ...
    const fs = require('fs')
    
    http.createServer(function(req, res) {
        const url2 = url.parse(req.url)
    
        if(url2.pathname == '/') {
            fs.createReadStream(__dirname+'/index.html').pipe(res)
        }
    })
    .listen(3001)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    __dirname是node自带的一个变量,值为当前目录路径。
    这样,当访问根路径时,html文件将出现在页面上。

    使用node.js搭建原生服务器基础部分就讲完了,不过现在已没人使用它来搭建服务器啦,下面介绍nodejs搭建服务器的热门框架,express和koa

    二 使用express框架搭建服务器

    在原生搭建中,我们需要使用url模块对url进行分析,使用if判断不同的路由,以执行不同的代码,当路由变多时,代码冗杂在一起。

    express框架对路由进行了封装,它自动判断当前请求的路由将其分发到对应的回调函数中,这就是express框架特有的路由系统。

    我们首先引入express模块(这是需要使用npm install express安装的),并创建express对象。

    const express = require('express')
    const app = express()
    
    • 1
    • 2

    express是一个工厂函数,返回一个可使用的对象,该对象可以挂载路由处理逻辑,和开启接口监听。

    ...
    app.get('/favicon.ico', function(req, res) {
        res.status(200)
        res.send('hello')
        return
    })
    app.listen(3001)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在express中,我们不再需要url模块和querystring模块,框架为我们完成了封装。

    我们可以使用req.query来获取参数。

    ...
    app.get('/', function(req, res) {
        const query = req.query
        res.param = query.action
        res.status(200)
        res.send(res.param)
    })
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    但是在返回html文件时,我们仍需要引入fs模块,只是使用格式有所变化。

    const fs = require('fs')
    ...
    app.get('/', function(req, res) {
        res.send(fs.readFileSync(__dirname+'/index.html', 'utf-8'))
    })
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在上面的代码中看到,在设置返回内容时,有也一些语法变化,更加简洁了。

    express框架主要做的事情就是这些:

    1. 路由系统:请求分发
    2. 附带url参数处理,在res中可以使用快捷api获取
    3. 返回res时语法更加简洁,并且会自动处理返回数据的包格式
    4. 提供具有洋葱模型的中间件

    现在来讲一下第四条,这可以说是最重要的一条了。

    express提供了中间件开发模式,而koa完善了该模式。

    简单的说,就是注册多个回调函数,当路由被触发时,沿着顺序执行多个回调函数,回调函数中接受next参数。

    当调用next()时,该回调函数暂停,进行下一个回调函数,当回调函数队列执行完毕,继续执行前面暂停的函数,直到回到第一个函数。

    下面这段代码的执行结果是 1 2 3 发出响应。

    app.get('/game', function(req, res, next) {
        const query = req.query
        res.param = query.action
        console.log(1)
        next()
        console.log(3)
        res.status(200)
        res.send(game(res.param))
    }, function(req, res) {
        console.log(2)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    但是,如果在后面的函数中执行异步操作,next不会等待异步完成,而是在同步代码执行完后就继续执行next后的代码。

    这是express的关键缺点之一,也是很多人选择koa的原因。

    三 使用koa框架搭建服务器

    koa是一个轻量级的框架,轻到它没有自己的路由系统,但是它提供了路由系统的中间件,只要引入就可以使用,使用方法和express差不多,只是语法有变化。

    首先我们引入koa(koa需要使用npm install安装),获得koa实例。

    在获得实例这里koa和express有所不同,koa使用new创建。

    const koa = require('koa')
    
    const app = new koa()
    
    • 1
    • 2
    • 3

    引入路由插件(中间件)koa-mount,封装路由逻辑,启动接口监听。

    另外,在路由中不用send了,给ctx.body赋值即可。

    const fs = require('fs')
    const koa = require('koa')
    const mount = require('koa-mount')
    
    const app = new koa()
    
    app.use(
        mount('/favicon.ico', function(ctx){
            ctx.status = 200
        })
    )
    app.use(
        mount('/', function(ctx){
            ctx.status = 200
            ctx.body = fs.readFileSync(__dirname+'/index.html', 'utf-8')
        })
    )
    app.listen(3001)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    koa对异步进行了处理,中间件的回调函数是可以加async前缀的,在next前加await前缀,next会等待异步完成后再执行后面的内容。

    下面是一个koa中间件语法的示范。

    猜猜看下面代码的执行结果是什么?

    const gamekoa = new koa()
    gamekoa.use(
        async function(ctx, next){
            console.log(11)
            await next()
            console.log(12)
    })
    gamekoa.use(
        async function(ctx, next){
            return new Promise((res) => {
                console.log(21)
                ctx.status = 200;
                ctx.body = '122333'
                setTimeout(() => {
                    console.log(22)
                    res()
                })
            })
        }
    )
    app.use(
        mount('/game', gamekoa)
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    上面代码执行结果为11 21 22 12,值得强调的是,即使在输出21后返回了数据,也不会中断中间件代码的执行,在数据返回后剩下的代码仍然执行了。

  • 相关阅读:
    世界杯将至,体育类加密项目迎来春天?
    Leetcode 73 矩阵置0
    JDK8新特性--函数式接口--(Consumer的概念理解,模拟练习,企业实战)全流程彻底搞懂
    荧光染料Cy7 酰肼,Cy7 hydrazide,Cy7 HZ参数及结构式解析
    音视频报警可视对讲15.6寸管理机
    leetcode做题笔记199. 二叉树的右视图
    初始JDBC 编程
    Python中的元组
    BUFLAB
    CISSP学习笔记:管理安全运营
  • 原文地址:https://blog.csdn.net/weixin_45809580/article/details/126852234