0

    ​Node.js系列十 - express开发web服务器

    2023.04.21 | admin | 232次围观

    一. Express初体验1.1. 认识Web框架

    前面我们已经学习了使用http内置模块来搭建Web服务器,为什么还要使用框架?

    目前在Node中比较流行的Web服务器框架是express、koa;

    express早于koa出现,并且在Node社区中迅速流行起来:

    1.2. express的安装

    express的使用过程有两种方式:

    方式一:安装express-generator

    npm install -g express-generator

    创建项目:

    express express-demo

    项目目录如下:

    ├── app.js
    ├── bin
    │   └── www
    ├── package-lock.json
    ├── package.json
    ├── public
    │   ├── images
    │   ├── javascripts
    │   └── stylesheets
    │       └── style.css
    ├── routes
    │   ├── index.js
    │   └── users.js
    └── views
        ├── error.jade
        ├── index.jade
        └── layout.jade

    我们可以安装依赖,将程序跑起来:

    npm install
    node bin/www

    方式二:从零学习搭建

    刚才创建的项目express项目,很多内容可能我们并不认识,所以刚开始我们最好从零来学习。

    初始化一个新的项目

    npm init -y

    express的安装:

    npm install express

    1.3. express初体验

    我们来创建自己的第一个express程序:

    const express = require('express');

    // 创建服务器
    const app = express();

    // /home的get请求处理
    app.get("/home", (req, res) => {
      res.end("Hello Home");
    });

    // /login的post请求处理
    app.post("/login", (req, res) => {
      res.end("Hello Login");
    });

    // 开启监听
    app.listen(8000, () => {
      console.log("服务器启动成功~");
    })

    我们会发现,之后的开发过程中,可以方便的将请求进行分离:

    当然,这只是初体验,接下来我们来探索更多的用法;

    1.4. 请求和响应

    请求的路径中如果有一些参数,可以这样表达:

    返回数据,我们可以方便的使用json:

    const express = require('express');

    const app = express();

    app.get('/users/:userId', (req, res, next) => {
      console.log(req.params.userId);
      res.json({username"coderwhy"level99});
    });

    app.listen(8000, () => {
      console.log("静态服务器启动成功~");
    })

    二. Express中间件2.1. 认识中间件

    Express是一个路由和中间件的Web框架,它本身的功能非常少:

    中间件是什么呢?

    中间件中可以执行哪些任务呢?

    如果当前中间件功能没有结束请求-响应周期js上传图片到项目服务器上,则必须调用next()将控制权传递给下一个中间件功能,否则js上传图片到项目服务器上,请求将被挂起。

    中间件函数调用的元素:

    image-202011012053338432.2. 应用中间件

    那么,如何将一个中间件应用到我们的应用程序中呢?

    我们先来学习use的用法,因为methods的方式本质是use的特殊情况;

    案例一:最普通的中间件

    之所以称之为最普通的中间件,是因为无论是什么path、methods都会应用该中间件;

    const express = require('express');

    const app = express();

    app.use((req, res, next) => {
      console.log("common middleware 01");
      next();
    })

    app.use((req, res, next) => {
      console.log("common middleware 02");
      res.end("Hello Common Middleware~");
    })

    app.listen(8000, () => {
      console.log("中间件服务器启动成功~");
    })

    中间件的执行顺序:

    案例二:path匹配中间件

    如果我们希望匹配一个明确的路径,也可以使用use方法:

    // 案例二: 路径匹配中间件
    app.use('/home', (req, res, next) => {
      console.log("home middleware 01");
      next();
    });

    app.use('/home', (req, res, next) => {
      console.log("home middleware 02");
      next();
      res.end("Hello Home middleware");
    });

    app.use((req, res, next) => {
      console.log("common middleware");
    });

    案例三:path和method匹配中间件

    // 案例三: method匹配中间件
    app.get('/home', (req, res, next) => {
      console.log("home get middleware");
      next();
    })

    app.post('/login', (req, res, next) => {
      console.log("login post middleware");
      next();
    });

    app.use((req, res, next) => {
      console.log("common middleware");
    });

    案例四:注册多个中间件

    // 案例四: 注册多个中间件
    const homeMiddleware1 = (req, res, next) => {
      console.log('home middleware 01');
      next();
    }

    const homeMiddleware2 = (req, res, next) => {
      console.log('home middleware 02');
      next();
    }

    const homeHandle = (req, res, next) => {
      res.end("Hello Home~");
    }

    app.get('/home', homeMiddleware1, homeMiddleware2, homeHandle);

    2.3. 应用其他中间件

    并非所有的中间件都需要我们从零去编写:

    2.3.1. request解析中间件

    在客户端发送post请求时,会将数据放到body中:

    我们这里先使用json传递给服务器body:

    json传递body

    不进行解析时的操作:

    app.post('/login', (req, res, next) => {
      req.on('data', (data) => {
        console.log(data.toString());
      })
      req.on('end', () => {
        res.end("登录成功~");
      });
    });

    我们也可以自己编写中间件来解析JSON:

    app.use((req, res, next) => {
      if (req.headers['content-type'] === 'application/json') {
        req.on('data', (data) => {
          const userInfo = JSON.parse(data.toString());
          req.body = userInfo;
        })
        req.on('end', () => {
          next();
        })
      } else {
        next();
      }
    })

    app.post('/login', (req, res, next) => {
      console.log(req.body);
      res.end("登录成功~");
    });

    但是,事实上我们可以使用expres内置的中间件或者使用body-parser来完成:

    app.use(express.json());

    app.post('/login', (req, res, next) => {
      console.log(req.body);
      res.end("登录成功~");
    });

    如果我们解析的是 application/x-www-form-urlencoded:

    form传递body

    我们可以使用express自带的 urlencoded函数来作为中间件:

    app.use(express.json());
    app.use(express.urlencoded({extendedtrue}));

    app.post('/login', (req, res, next) => {
      console.log(req.body);
      res.end("登录成功~");
    });

    2.3.2. 日志记录中间件

    如果我们希望将请求日志记录下来,那么可以使用express官网开发的第三方库:morgan

    安装morgan:

    npm install morgan

    直接作为中间件使用即可:

    const loggerWriter = fs.createWriteStream('./log/access.log', {
      flags'a+'
    })
    app.use(morgan('combined', {stream: loggerWriter}));

    2.3.3. 上传文件中间件

    图片上传我们可以使用express官方开发的第三方库:multer

    npm install multer

    上传文件,并且默认文件名:

    const upload = multer({
      dest"uploads/"
    })

    app.post('/upload', upload.single('file'), (req, res, next) => {
      console.log(req.file.buffer);
      res.end("文件上传成功~");
    })

    添加文件名后缀:

    const storage = multer.diskStorage({
      destination(req, file, cb) => {
        cb(null"uploads/")
      },
      filename(req, file, cb) => {
        cb(nullDate.now() + path.extname(file.originalname));
      }
    })

    const upload = multer({
      storage
    })

    app.post('/upload', upload.single('file'), (req, res, next) => {
      console.log(req.file.buffer);
      res.end("文件上传成功~");
    })

    我们也可以上传多张图片:

    app.use('/upload', upload.array('files'), (req, res, next) => {
      console.log(req.files);
    });

    如果我们希望借助于multer帮助我们解析一些form-data中的普通数据,那么我们可以使用any:

    image-20201104165039444

    app.use(upload.any());

    app.use('/login', (req, res, next) => {
      console.log(req.body);
    });

    2.4. 请求和响应

    客户端传递到服务器参数的方法常见的是5种:

    2.4.1. 请求解析

    方式一:params

    请求地址::8000/login/abc/why

    获取参数:

    app.use('/login/:id/:name', (req, res, next) => {
      console.log(req.params);
      res.json("请求成功~");
    })

    方式二:query

    请求地址::8000/login?username=why&password=123

    获取参数:

    app.use('/login', (req, res, next) => {
      console.log(req.query);

      res.json("请求成功~");
    })

    2.4.2. 响应方式

    end方法

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论