web服务器的搭建方法(nodejs,express)和中间件的使用

目录

Nodejs创建web服务器(不常用)

创建服务器步骤

搭建过程中需要的

Express框架开发

基本信息

 express的安装和使用

初始化项目并安装express

初体验:express创建web服务器

express中的app对象

1.app.get( 路径,兼听函数 )

2.app.post(路径,兼听函数 )

3. app.all(路径,兼听函数 )

express的response对象

1. res.send( 字符串|对象 )。

2.res.sendFile( absolute filepath )

express的request对象

1)req.query

 2)req.params

 使用步骤

 开发工具的使用(nodemon热更新 ,Rest Client )

nodemon热更新工具

Rest Client

路由Router

什么是路由?

express中Router的作用?以及Router要解决的问题?

Express中的路由(Node的路由)

匹配流程

express.Router 模块化路由

总结(原生nodejs和express的req,res)

express的中间件

什么是中间件?

简介

中间件的好处

中间件执行流程

使用中间件

 中间节的基本使用

用法一:app.use()

用法二:router.use()

中间件加前缀

用法一:app.use(前缀,中间件函数):使用自定义中间件时

用法二:app.use(前缀,中间件函数):使用模块化路由时 【重点】

 用法三:router.use(前缀,中间件函数):使用自定义中间件时

中间件种类

应用级别的中间件

错误中间件

逻辑错误 :就是含有err,req,res,next四个形参的自定义中间件

内置中间件

开放静态资源:express.static(绝对路径)

接收post参数

1)、express.urlencoded()内置中间件用来接收以post方式的键值对格式发送的参数:

2)、express.json()内置中间件用来接收以post方式的json格式发送的参数:

第三方中间件

小图标

图片验证码


Nodejs创建web服务器(不常用)

为什么要创建web服务器?

只有我们把nodejs程序通过web服务器发布出去之后,别人才能通过互联网来访问我们的nodejs程序,否则也只是在本地运行我们的nodejs程序。

创建服务器步骤

//引入http模块
const http = require('http');
// console.log(http);

//创建web服务器:
const server = http.createServer();
// console.log(server);

//监听事件:server.on('事件名',回调方法);
//req对象:request请求对象
//res对象:response响应对象
server.on('request', function(req, res) {
  
    res.end('Yes OK');
    // res.end('Hello web'); //结束响应、res.end()必须且只能使用一次
});


//监听端口:
server.listen(3000, function() {
    console.log('3000端口');
});

搭建过程中需要的

设置响应头信息。res.writeHead(200,{'Content-Type':"text/html;charset=utf8"});

打印请求消息。method和url

//引入http模块
const http = require('http');
// console.log(http);

//创建web服务器:
const server = http.createServer();
// console.log(server);

//监听事件:server.on('事件名',回调方法);
//req对象:request请求对象
//res对象:response响应对象
server.on('request', function(req, res) {
    console.log(req.url);

    //res.setHeader()或res.writeHead():设置响应的头信息
    // res.setHeader('content-type', 'text/html;charset=utf-8');
    res.writeHead(200, 'ok', { 'content-type': 'text/html;charset=utf-8' });

    res.write('

张三

'); //返回响应的内容、res.write()可以多次使用 res.write('

年龄:20

'); res.end('Yes OK'); // res.end('Hello web'); //结束响应、res.end()必须且只能使用一次 }); //监听端口: server.listen(3000, function() { console.log('3000端口'); });

Express框架开发

基本信息

Express是基于基于 Nodejs平台,快速、开放、极简的 Web 开发框架(后端开发框架)。

中文地址:Express - 基于 Node.js 平台的 web 应用开发框架 - Express 中文文档 | Express 中文网icon-default.png?t=LA92https://www.expressjs.com.cn/

官网地址:Express - Node.js web application framework

作用:使用 Express,我们可以方便、快速的创建 Web 网站的服务器或 API 接口(纯json数据)的服务器。

本质上:express是一个第三方包存在于npm社区中。

 API(Application Programming Interface,应用程序接口)是一些预先定义的接口(如函数、HTTP接口),或指软件系统不同组成部分衔接的约定。

 express的安装和使用

初始化项目并安装express

注意:在项目根目录下执行下面的命令:

npm  i   express

初体验:express创建web服务器

//引入express框架
const express = require('express');
// console.log(express);

//创建应用:
const app = express();
// console.log(app);

//监听端口:
app.listen(4040, () => {
    console.log('4040端口');
});

express中的app对象

1.app.get( 路径,兼听函数 )

注意:所有的路径必须以/开头

匹配以get方式发送过来的请求

以get方式发送请求的有:

1)、在浏览器地址栏中;

2)、a标签中的href属性;

3)、form标签中的method='get'或省略method属性; //只能以get方式的查询字符串格式发送参数

4)、javascript中使用location.href进行页面跳转;

2.app.post(路径,兼听函数 )

注意:所有的路径必须以/开头

匹配以post方式发送过来的请求

3. app.all(路径,兼听函数 )

匹配以任意方式发送过来的请求,app.all()方法通常放在最后面来处理404错误。

express的response对象

1. res.send( 字符串|对象 )。

返回响应,res.send()方法相当于原生nodejs中的res.setHeader()和res.end()这两个方法

2.res.sendFile( absolute filepath )

将某个文件的内容读取出来并作为响应返回给客户端。

express的request对象

1)req.query

req.query属性用来接收get方式的查询字符串格式发送的参数,get方式的查询字符串格式的参数如下:

 http://localhost:4040/teacher?参数名=参数值&参数名2=参数值2

 2)req.params

专业名称:动态路径(路由)

req.params属性用来接收get方式的path路径格式发送的参数,get方式的path路径格式的参数如下:http://localhost:4040/zhuce/参数值1/参数值2/参数值3

 使用步骤

第一步:使用app.get()设置路径时参数部分要使用:变量名来表示,如:

//详情页面
//app.get('/detail/:变量名1/:变量名2', (req, res) => {

 // 
 //   res.send(`详情页`);
//});

//详情页面
app.get('/detail/:uid/:email', (req, res) => {

    console.log(req.params);
    let { uid = '', email = '' } = req.params;

    res.send(`详情页${uid}  ${email}`);
});

 开发工具的使用(nodemon热更新 ,Rest Client )

nodemon热更新工具

如果以热更新方式运行某个应用程序,则热更新会检查当前应用程序文件的代码是否发生变化,若有变化则热更新工具会自动停止并重新运行当前应用程序,而不需要手动频繁停止、运行某个应用程序。

第一步:安装nodemon热更新工具:

在dos小黑窗的任意目录中执行下面的命令:

 npm  i   nodemon -g

关于-g参数的说明: 【重点】

1)、使用-g参数安装的第三方包默认存储在:C:\Users\当前用户\AppData\Roaming\npm;

2)、使用-g参数安装某个包时可以在dos小黑窗的任意目录来执行安装命令,而不一定要在项目的根目录中执行安装命令;

3)、同一台电脑只需要安装一次即可;

第二步:以热更新方式来运行某个应用程序:

 E:\web_beijing\day07\代码>nodemon 5-作业-zhuce.js

Rest Client

Rest Client是vscode的一个插件,该插件是用来模拟HTTP协议中的各种请求方式发送请求的,通常用来调试服务端的接口程序。

第一步:在vscode工具中安装Rest Client插件;

第二步:在任意目录中创建以.http结尾的文件,在这个以.http结尾文件中定义要调用的服务端程序(接口程序),格式如下:

@urls=http://localhost:5000

POST {{urls}}/mytest HTTP/1.1


###
GET {{urls}}/[email protected] HTTP/1.1

###
GET {{urls}}/login/110/zhangsan HTTP/1.1

路由Router

什么是路由?

广义上来讲,路由就是映射关系。对于我们网络请求中的路由是:每一次请求对应每一个请求处理的函数。

路由就是根据请求中的不同path路径返回不同的响应,在express框架中设计路由的方式有两种:

第一种:使用app.get()、app.post()、app.all()方法来设计路由;

第二种:使用模块化方式来设计路由;

express中Router的作用?以及Router要解决的问题?

(1): express.Router 可以认为是一个微型的只用来处理中间件与控制器的 app, 它拥有和 app 类似的方法,例如 get、post等等。

(2): router它解决了直接把 app 暴露给其它模块使得 app 有被滥用的风险

Express中的路由(Node的路由)

 app.method( path,callback )

参数说明:

method:代表请求方式,比如get,post

path:代表请求路径

callback:代表回调函数,用户请求匹配到路由以后要做的事情。

匹配流程

web服务器的搭建方法(nodejs,express)和中间件的使用_第1张图片 

express.Router 模块化路由

为什么要采用模块化路由?

因为使用app.get()、app.post()、app.all()来设计路由时会把所有路由都混在一起,后期维护不方便。

采用模块化路由的语法来设计路由的步骤: 【重点】

第一步:新建模块化路由文件user.js,并在文件中设计路由,user.js文件中的语法格式为:

const express = require('express');
const router = express.Router();

//设计路由:router.get()、router.post()、router.all()


//暴露router对象:
module.exports = router

第二步:使用上面定义好的模块化路由文件user.js,代码如下:

注意:使用模块化路由定义的路由: app.use([路径,]回调方法);

const express = require('express');

const app = express();

app.listen(5000, () => {
    console.log('5000端口');
});

//引入采用模块化路由语法定义的路由文件
let userRouter = require('./user.js');
// console.log(userRouter);
//使用模块化路由语法定义的路由:app.use([路径,]回调方法);
app.use(userRouter);

总结(原生nodejs和express的req,res)

总结:

原生nodejs的res对象上的方法:

res.setHeader()、res.writeHead():设置响应的头信息

res.write():设置要返回的响应数据,可以多次使用

res.end():结束响应,必须且只能使用一次

原生nodejs的req对象上的方法:

req.url:获取请求的完整URL地址

express框架的res对象上的方法:

res.send(字符串|json对象):设置要返回的响应数据,相当于原生nodejs中的res.setHeader()和res.end()这两个方法,不能同时执行多次res.send()方法。

res.sendFile(文件的绝对路径):将某个文件内容读取出来并作为响应返回给客户端;

express框架的req对象上的属性:

req.query:接收get方式的查询字符串格式发送的参数;

req.params:接收get方式的path路径格式发送的参数;

express的中间件

什么是中间件?

中间件就是在接收请求之后返回响应之前要执行的函数,而这些函数有一定的业务处理能力,可以理解中现实生活中的车间。

express的中间件分为:自定义中间件、内置中间件、第三方中间件;

简介

中间件(Middleware),特指业务流程的中间处理环节。我们可以把中间件比作工厂中的车间。比如:在处理铁矿石的时候,一般都要经过三个处理环节,从而保证处理过后的矿石达到标准的钢材。处理铁矿石的这三个中间处理环节,就可以叫做中间件。而中间件其实是路由的升级,也能达到请求的匹配,只不过必须要进行下一步处理,以到达最终的路由匹配,就像在工厂中生产产品,最后必须要出厂。

中间件的好处

中间件机制使得Web应用具备良好的可扩展性和组合性。

1、会使用中间层作为数据的中转站(解决跨域)

好处:

1,没有跨域

2、可以对接收的数据进行二次处理。(过滤) 小程序 ,公众号,工作项目

中间件执行流程

当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。但是必须要有一个最终的匹配路由进行响应给客户端结果。

 web服务器的搭建方法(nodejs,express)和中间件的使用_第2张图片

 

使用中间件

 app.use( [前缀,]中间件函数 )
router.use([前缀,]中间件函数)

中间件要注意的事项:【重点】

1)、使用中间件的代码通常会放在所有路由的最前面;

2)、在自定义中间件内部当所有的业务代码执行完成后,要手动调用next()方法;

3)、next()方法会查找并执行后面能匹配上的路由;

4)、根据实际情况可以连续执行多个中间件;

5)、当中间件内部的业务代码出现异常时则通常会把异常信息当作next()方法的参数,则next()方法默认会把异常信息直接输出到屏幕上,如果需要对next()方法中的参数进行二次处理时则需要定义含err,req,res,next四个形参的逻辑错误处理中间件;

 中间节的基本使用

用法一:app.use()

const experss = require('express');
const timestamp = require('time-stamp');
const app = experss();
app.listen(3000, () => {
    console.log(`web服务器工作在3000端口`);
});

//req:request请求对象
//res:response响应对象
//next:next()为方法
function getCurTimes(req, res, next) {
    // console.log(req, res, 222);
    // console.log(next, 1111);
      //生成日期时间
        let curtimes = timestamp('YYYY-MM-DD HH:mm:ss');
        req.tiems = curtimes;
        res.t = curtimes;
        // console.log(curtimes, 999);
        next(); //next()方法查找并执行后面能匹配上的路由
}

function myDemo(req, res, next) {
    console.log('Hello web');
    next();
}

//使用中间件语法:
app.use(getCurTimes);
// app.use(myDemo);


//老师界面:
app.get('/teacher', (req, res) => {

    res.send(`这是老师的界面:${req.tiems} ${res.t}`);
});

// app.use(getCurTimes);

//学生界面:
app.get('/student', (req, res) => {

    res.send(`学生界面:${req.tiems}`);
});

用法二:router.use()

模块化路由文件index.js的代码如下:

//模块化路由语法来设计路由:
const express = require('express');
const router = express.Router();

//定义中间件函数:
function myTest(req, res, next) {
    console.log('Hello WEB');
    next();
}

router.use(myTest);

router.get('/banners', (req, res) => {

    res.send('轮播图');
});


router.post('/mycourse', (req, res) => {

    res.send('首页同步课程');
});

module.exports = router;

在app.js文件中使用上面定义的模块化路由,代码如下:

const experss = require('express');
const app = experss();
app.listen(5000, () => {
    console.log(`web服务器工作在5000端口`);
});

let indexRouter = require('./3-index.js');
app.use(indexRouter);

中间件加前缀

用法一:app.use(前缀,中间件函数):使用自定义中间件时

const experss = require('express');
const timestamp = require('time-stamp');
const app = experss();
app.listen(3000, () => {
    console.log(`web服务器工作在3000端口`);
});

// let obj = {};
// obj.x = 11;
// console.log(obj);

//req:request请求对象
//res:response响应对象
//next:next()为方法
function getCurTimes(req, res, next) {
    // console.log(req, res, 222);
    // console.log(next, 1111);

    if (1) { //正常
        let curtimes = timestamp('YYYY-MM-DD HH:mm:ss');
        req.tiems = curtimes;
        res.t = curtimes;
        // console.log(curtimes, 999);
        next(); //next()方法查找并执行后面能匹配上的路由
    } else { //异常
        next('这是错误信息');
    }


}

function myDemo(req, res, next) {
    console.log('Hello web');
    next();
}

//使用中间件语法:
// app.use(getCurTimes);
app.use('/student', getCurTimes);
// app.use(myDemo);


//老师界面:
app.get('/teacher', (req, res) => {

    res.send(`这是老师的界面:${req.tiems} ${res.t}`);
});

// app.use(getCurTimes);

//学生界面:
app.get('/student', (req, res) => {

    res.send(`学生界面:${req.tiems}`);
});

//逻辑错误处理中间件:
function proErrors(err, req, res, next) {
    console.log(err, 1111);
    //  fs.writeFileSync(path.join(__dirname,'err.log'));

    res.send(`出错了:${err}`);
}
app.use(proErrors);

用法二:app.use(前缀,中间件函数):使用模块化路由时 【重点】

注意:3-index.js这个模块化路由文件中的所有路由路径以/api开头

const experss = require('express');
const app = experss();
app.listen(5000, () => {
    console.log(`web服务器工作在5000端口`);
});

let indexRouter = require('./3-index.js');
//  app.use(indexRouter);
//注意:3-index.js这个模块化路由文件中的所有路由路径以/api开头
app.use('/api', indexRouter);

 用法三:router.use(前缀,中间件函数):使用自定义中间件时

 

//模块化路由语法来设计路由:
const express = require('express');
const router = express.Router();

//定义中间件函数:
function myTest(req, res, next) {
    console.log('Hello WEB');
    next();
}

router.use('/mycourse', myTest);

router.get('/banners', (req, res) => {

    res.send('轮播图');
});


router.post('/mycourse', (req, res) => {

    res.send('首页同步课程');
});

module.exports = router;

中间件种类


应用级别的中间件

app.get

app.post

 

错误中间件

404错误:

注意:404错误中间件要放在所有路由的最后面

用法一:在模块化路由文件中定义

//模块化路由语法来设计路由:
const express = require('express');
const path = require('path');
const router = express.Router();

//定义中间件函数:
function myTest(req, res, next) {
    console.log('Hello WEB');
    next();
}

router.use('/mycourse', myTest);

router.get('/banners', (req, res) => {

    res.send('轮播图');
});


router.post('/mycourse', (req, res) => {

    res.send('首页同步课程');
});

function err404(req, res, next) {

    // res.send('404错误');
    res.sendFile(path.join(__dirname, '404.html'));
}

router.use('*', err404);
// router.use('*', (req, res, next) => {
//     res.send('404错误');
// });

module.exports = router;

用法二:使用app对象上的use()方法

逻辑错误 :就是含有err,req,res,next四个形参的自定义中间件

const experss = require('express');
const timestamp = require('time-stamp');
const app = experss();
app.listen(3000, () => {
    console.log(`web服务器工作在3000端口`);
});

// let obj = {};
// obj.x = 11;
// console.log(obj);

//req:request请求对象
//res:response响应对象
//next:next()为方法
function getCurTimes(req, res, next) {
    // console.log(req, res, 222);
    // console.log(next, 1111);

    if (1) { //正常
        let curtimes = timestamp('YYYY-MM-DD HH:mm:ss');
        req.tiems = curtimes;
        res.t = curtimes;
        // console.log(curtimes, 999);
        next(); //next()方法查找并执行后面能匹配上的路由
    } else { //异常
        next('这是错误信息');
    }
}

function myDemo(req, res, next) {
    console.log('Hello web');
    next();
}

//使用中间件语法:
// app.use(getCurTimes);
app.use('/student', getCurTimes);
// app.use(myDemo);


//老师界面:
app.get('/teacher', (req, res) => {

    res.send(`这是老师的界面:${req.tiems} ${res.t}`);
});

// app.use(getCurTimes);

//学生界面:
app.get('/student', (req, res) => {

    res.send(`学生界面:${req.tiems}`);
});

//逻辑错误处理中间件:
function proErrors(err, req, res, next) {
    console.log(err, 1111);
    //  fs.writeFileSync(path.join(__dirname,'err.log'));

    res.send(`出错了:${err}`);
}
app.use(proErrors);

内置中间件

开放静态资源:express.static(绝对路径)

注意:将某个目录开放之后在访问时不需要带上该目录名称

中文文档参考地址:利用 Express 托管静态文件 - Express 中文文档 | Express 中文网

什么是开放静态资源?

就是让用户通过我们的web服务器来访问静态资源(比如:.js文件、.css文件、.html文件、图片文件)。

const experss = require('express');
const path = require('path');
const app = experss();
app.listen(3000, () => {
    console.log(`web服务器工作在3000端口`);
});

//使用内置中间件express.static()来开放静态资源:
//注意:将某个目录开放之后在访问时不需要带上该目录名称
// app.use('/img', experss.static(path.join(__dirname, 'img')));
// app.use('/css', experss.static(path.join(__dirname, 'css')));
// app.use('/js', experss.static(path.join(__dirname, 'js')));
app.use(experss.static(path.join(__dirname, 'public')));


//显示登录界面:
app.get('/login', (req, res) => {

    res.sendFile(path.join(__dirname, 'login.html'));
});

// //显示图片:
// app.get('/img/good_banner3.png', (req, res) => {

//     res.sendFile(path.join(__dirname, 'img/good_banner3.png'));
// });

接收post参数

1)、express.urlencoded()内置中间件用来接收以post方式的键值对格式发送的参数:

中文文档参考地址:Express 4.x - API Reference - Express 中文文档 | Express 中文网

app.use(express.urlencoded({extended:false}))

在某.http文件中写入类似于下面格式的内容用来模拟post方式发送键值对格式的参数:

@urls= http://localhost:5000

POST {{urls}}/mytest HTTP/1.1

###
POST {{urls}}/dologin HTTP/1.1
Content-Type:application/x-www-form-urlencoded

uname=李四&age=20&tel=110

然后在某个路由中使用req.body来接收post方式发送的参数:


const experss = require('express');
const path = require('path');
const app = experss();
app.listen(5000, () => {
    console.log(`web服务器工作在5000端口`);
});

//使用内置中间件express.static()来开放静态资源:
//注意:将某个目录开放之后在访问时不需要带上该目录名称
// app.use('/img', experss.static(path.join(__dirname, 'img')));
// app.use('/css', experss.static(path.join(__dirname, 'css')));
// app.use('/js', experss.static(path.join(__dirname, 'js')));
app.use(experss.static(path.join(__dirname, 'public')));

//使用内置中间件express.urlencoded()接收post方式的键值对格式发送的参数:
app.use(experss.urlencoded({ extended: false }));

app.post('/dologin', (req, res) => {

    console.log(req.body, 111);
    let { uname, age, tel } = req.body;

    res.send(`处理登录 ${uname} ${age} ${tel}`);
});

2)、express.json()内置中间件用来接收以post方式的json格式发送的参数:

app.use(express.json())

中文文档参考地址:Express 4.x - API Reference - Express 中文文档 | Express 中文网

在某.http文件中写入类似于下面格式的内容用来模拟post方式发送json格式的参数:

@urls= http://localhost:5000

POST {{urls}}/mytest HTTP/1.1

###
POST {{urls}}/myjson HTTP/1.1
Content-Type: application/json

{"usr":"lisi","email":"[email protected]","y":100}

###

然后在某个路由中使用req.body来接收post方式发送的参数:

 

const experss = require('express');
const path = require('path');
const app = experss();
app.listen(5000, () => {
    console.log(`web服务器工作在5000端口`);
});

//使用内置中间件express.static()来开放静态资源:
//注意:将某个目录开放之后在访问时不需要带上该目录名称
// app.use('/img', experss.static(path.join(__dirname, 'img')));
// app.use('/css', experss.static(path.join(__dirname, 'css')));
// app.use('/js', experss.static(path.join(__dirname, 'js')));
app.use(experss.static(path.join(__dirname, 'public')));

//使用内置中间件express.urlencoded()接收post方式的键值对格式发送的参数:
app.use(experss.urlencoded({ extended: false }));
//使用内置中间件express.json()接收post方式的json格式发送的参数:
app.use(experss.json());


app.post('/myjson', (req, res) => {
    console.log(req.body, 9999);
    res.send('post参数:');
});

第三方中间件

小图标

serve-favicon

图片验证码

svg-captcha

npm install svg-captcha

svgCaptcha.create(options)`

var svgCaptcha = require('svg-captcha');
 
app.get('/captcha', function (req, res) {
    var captcha = svgCaptcha.create();
    req.session.captcha = 验证码文本;
    
    res.type('svg');
    res.status(200).send(captcha.data);
});

如果没有传递任何选项,您将获得一个由四个字符组成的随机字符串和相应的 svg。

  • size: 4 // 随机字符串的大小

  • ignoreChars: '0o1i' // 过滤掉一些像 0o1i 这样的字符

  • noise: 1 // 噪声线数

  • color: true // 字符将具有不同的颜色而不是灰色,如果设置了背景选项则为真

  • background: '#cc9966' // svg 图像的背景颜色

此函数返回一个具有以下属性的对象:

  • data: string // svg 路径数据

  • text: string // 验证码文本

svgCaptcha.createMathExpr(options)

与创建 api 类似,您拥有上述选项以及 3 个附加选项:

  • mathMin: 1 // 数学表达式的最小值

  • mathMax: 9 // 数学表达式的最大值

  • mathOperator: + // 要使用的运算符, +, -or +-(for random +or -)

此函数返回一个具有以下属性的对象:

  • data: string // 数学表达式的 svg

  • text: string // 数学表达式的答案

svgCaptcha.loadFont(url)

加载您自己的字体并覆盖默认字体。

  • url: string // 字体路径 这个api是opentype.js的loadFont api的包装器。 您可能需要围绕各种选项进行试验,以使您自己的字体可访问。 见下面的api。

svgCaptcha.options

获得对全局设置对象的访问权。它用于 create 和 createMathExpr api 作为默认选项。

除了大小、噪声、颜色和背景之外,您还可以设置以下属性:

  • width: number // 验证码的宽度

  • height: number // 验证码高度

  • fontSize: number // 验证码文本大小

  • charPreset:string // 随机字符预设

svgCaptcha.randomText([size|options])

返回一个随机字符串。

svgCaptcha(text, options)

根据提供的文本返回 svg 验证码。

在 1.1.0 之前的版本中,您必须调用这两个函数, 现在您可以调用 create() 来保存一些按键;)。

你可能感兴趣的:(express,node.js,前端,前端,javascript,开发语言,node.js,中间件)