express使用总结,中间件示例

express

express:目前最流行的nodejs框架、

++windows系统的重命名原理是新建一个文件,然后将原来文件中的内容拷入新建文件夹,所以最好将node_modules删掉重装一下++

express的基本使用

安装:

npm install express --save

const express=require('express');

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

// 是get请求
// 路由第一个参数的规则
// 路径  是一个pathname
// 路径路径可以是字符串,字符串模式或正则表达式。
// 路径需要跟参数一完全匹配才可以进入路由的处理
// 那么就会执行第二个参数的回调,处理该请求
app.get('/', (request, response)=>{
  response.write('hello world 你好');
  response.end();
});


// 启动服务
// 参数1: 端口号
// 参数2: 域名
// 参数3: 最大的连接数量
// app.listen(8000, 'localhost', 512, ()=>{})
app.listen(8000,(error)=>{
  if(error) throw error;
  console.log('server is run: http://localhost:8000');
})



// 路由第一个参数的规则
// 路径如果有‘:’修饰,那么这是一个参数

app.get('/users/:userId/books/:bookId', (request, response)=>{
    ....
}

next 指针

app.get('/', (request, response, next)=>{
  // request客户端的请求
  // response将要响应课客户端的响应对象
  // next指针    
  next();
});

路由处理的函可以传入多个或者以数组形式传入

app.get('/', func1);

app.get('/', func1, func2);

app.get('/', [
  func1,
  func2
], func3);

路由

路由是指应用程序端点(URI)的定义以及它们如何响应客户端请求。

URI包括url但不完全等于url

// GET method route
app.get('/', function (req, res) {
  res.send('GET request to the homepage')
})

// POST method route
app.post('/', function (req, res) {
  res.send('POST request to the homepage')
})

app.all('/secret', function (req, res, next) {
  console.log('Accessing the secret section ...')
  next() // pass control to the next handler
})

其他方法:

getpostputheaddeleteoptionstracecopylockmkcolmovepurgeunlockreportmkactivitycheckoutmergem-searchnotifysubscribeunsubscribepatchsearch

路由转换为无效JavaScript变量名称的方法:

app['m-search']('/', function ...

路由路径

路径路径可以是字符串,字符串模式或正则表达式。

路线参数
Route path: /users/:userId/books/:bookId
Request URL: http://localhost:3000/users/34/books/8989
req.params: { "userId": "34", "bookId": "8989" }
路由处理程序

路由处理程序可以采用函数,函数数组或两者的组合的形式。

next('route')绕过剩余的路由回调。

response响应方法
方法描述
res.download()提示要下载的文件。
res.end()结束响应过程。
res.json()发送JSON响应。
res.jsonp()用JSONP支持发送JSON响应。
res.redirect()重定向请求。
res.render()呈现视图模板。
res.send()发送各种类型的响应。
res.sendFile()以八位字节流的形式发送文件。
res.sendStatus()设置响应状态代码并将其字符串表示形式作为响应主体发送。
res.status()设置响应状态代码

response响应对象

app.get('/',(req,res)=>{
    let obj={a:1,b:2};
    
    //响应json数据
    res.json(obj);
    
  //让客户端下载资源
  res.download('../文件.zip');
  
  //响应jsonp格式的数据
  res.jsonp(obj);
  
   // 重定向
   res.redirect('/home');
   
   // write end 合体
    res.end(4);
    
  // 响应的是文件
   res.sendFile(__dirname + '/app.js');
   
    //响应状态码,并且statusMessage做为响应的内容
    res.sendStatus(404);
    
     // 等价的
  // res.statusCode = 200;
  // res.status(200);
})
app.all()

get post put … 不分请求方法,但是路径需要完全匹配
执行函数就会调用

app.all('/',(req,res,next)=>{
    ....
})
app.route()

如果处理请求的路径一样,但是处理函数内容不同,建议使用下面的方式处理

app.route('/book')
  .get(function (req, res) {
  res.send('Get a random book')
})
  .post(function (req, res) {
  res.send('Add a book')
})
  .put(function (req, res) {
  res.send('Update the book')
})

凡是由app可以调用的方法,router统统可以调用,router会自动判断res.url(get,post,detele,put…)

使用中间件

中间件功能是可以访问请求对象(req),响应对象(res)以及应用程序请求 - 响应周期中的下一个中间件功能的函数。下一个中间件函数通常用名为next的变量表示。

中间件功能可以执行以下任务:

  • 执行任何代码。

  • 对请求和响应对象进行更改。

  • 结束请求 - 响应循环。

  • 调用堆栈中的下一个中间件功能。

如果当前的中间件功能没有结束请求 - 响应周期,则它必须调用next()以将控制传递给下一个中间件功能。否则,请求将被挂起。

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)


//只有'/api'开头的请求,才会进入到中间件中
// use的第一个参数,起到过滤的功能
app.get('/api', function (req, res) {
  res.send('Hello World!')
});
/* 
/api    可以匹配
/api/     可以匹配
/apiabc     不可以匹配
/api/abc        可以匹配
/api/abc/abc....      可以匹配
 */

app.listen(3000)
app.use('/api', (req, res, next)=>{
  console.log('执行了1');  
  console.log(req.baseUrl); // /api
  console.log(req.url);  // /test
  console.log(req.originalUrl);  // /api/test
  req.name = 'hello wrold';
  next();
})

app.get('/api/test', (req, res)=>{
  console.log('执行了2');
  console.log(req.url);//  /api/test  
  console.log(req.name);  //hello world
  res.end('ok');
})
可配置的中间件
//File: my-middleware.js
module.exports = function(options) {
  return function(req, res, next) {
    // Implement the middleware function based on the options object
    next()
  }
}
//使用中间件
var mw = require('./my-middleware.js')
app.use(mw({ option1: '1', option2: '2' }))

Express应用程序可以使用以下类型的中间件:

  • Application-level middleware(应用程序级别中间件)

  • 路由器级中间件

  • 错误处理中间件

  • 内置中间件

  • 第三方中间件

Application-level middleware

这个例子显示了没有安装路径的中间件功能。每次应用程序收到请求时都会执行该功能。

var app = express()

app.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

此示例显示/user/:id路径上安装的中间件功能。该函数针对/user/:id路径上的任何类型的HTTP请求执行。

app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method)
  next()
})//      /user/007  /hello/123

这个例子显示了一个路由及其处理函数(中间件系统)。该函数处理对/user/:id路径的GET请求。

app.get('/user/:id', function (req, res, next) {
  res.send('USER')
})//      /user/007   /hello/123

下面是一个在装载点加载一系列中间件功能的例子,带有装载路径。它演示了一个中间件子堆栈,用于打印任何类型的HTTP请求到/user/:id路径的请求信息。

app.use('/user/:id', function (req, res, next) {
  console.log('Request URL:', req.originalUrl)
  next()
}, function (req, res, next) {
  console.log('Request Type:', req.method)
  next()
})

此示例显示处理GET请求到/user/:id路径的中间件子堆栈。

app.get('/user/:id', function (req, res, next) {
  console.log('ID:', req.params.id)
  next()
}, function (req, res, next) {
  res.send('User Info')
})

// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', function (req, res, next) {
  res.end(req.params.id)
})
自定义正向代理中间件
const map = {
  http: require('http'),
  https: require('https'),
}

module.exports = ({host, port, protocol = 'http'})=>{
  return (req, res, next)=>{
    map[protocol].request({
      hostname: host,
      port,
      path: req.originalUrl,
      method: 'GET'
    }, (response)=>{
      // 获得数据的content-type, content-length
      res.setHeader('content-type', response.headers['content-type']);
      res.setHeader('content-length', response.headers['content-length'] || '');
  
      response.on('data', (bf)=>{
        res.write(bf);
      })
      response.on('end', ()=>{
        res.end();
      })
  
    }).end();
  }
}
next(‘route’)
app.get('/user/:id', function (req, res, next) {
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
})

// handler for the /user/:id path, which renders a special page
app.get('/user/:id', function (req, res, next) {
  res.render('special')
})
路由器中间件
var app = express()
var router = express.Router()

// a middleware function with no mount path. This code is executed for every request to the router
router.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path
router.use('/user/:id', function (req, res, next) {
  console.log('Request URL:', req.originalUrl)
  next()
}, function (req, res, next) {
  console.log('Request Type:', req.method)
  next()
})

// a middleware sub-stack that handles GET requests to the /user/:id path
router.get('/user/:id', function (req, res, next) {
  // if the user ID is 0, skip to the next router
  if (req.params.id === '0') next('route')
  // otherwise pass control to the next middleware function in this stack
  else next()
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
})

// handler for the /user/:id path, which renders a special page
router.get('/user/:id', function (req, res, next) {
  console.log(req.params.id)
  res.render('special')
})

// mount the router on the app
app.use('/', router)
app.use('/api/user', require('./routes/userRouter'));
app.use('/api/jobs', require('./routes/JobsRouter'));
app.use('/api/company', require('./routes/companyRouter'));


这样就可以在userRouter,JobsRouter,companyRouter对对应的api进行统一的处理
错误处理中间件

错误处理中间件始终需要四个参数。您必须提供四个参数来将其标识为错误处理中间件功能。即使您不需要使用该next对象,也必须指定它以维护签名。否则,该next对象将被解释为常规中间件,并且将无法处理错误。

app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})
内置中间件

Express具有以下内置中间件功能:

  • express.static提供静态资源,如HTML文件,图像等。

  • express.json使用JSON有效负载分析传入的请求。(解析字典类型的数据)注:适用于Express 4.16.0+

  • express.urlencoded使用URL编码的有效负载分析传入的请求。(解析字符串格式的数据)注:适用于Express 4.16.0+

  • body-parser老的项目用这个中间件来解析,现在已经不推介使用了

express.static()调用得到是中间件
处理静态资源文件的

当请求为/static/*时,按照url路径在'./static'路径下查找资源,响应给客户端。
app.use('/static',express.static('./static'))

直接用nodeJs获取客户端post请求参数:

app.post('/list/test',(req,res)=>{
    console.log('接收到了客户端的post请求:/list/test');
  // post请求参数?
  let params = '';
  req.on('data', (bf)=>{
    params += bf;
  })
  req.on('end', (bf)=>{
    console.log(params);
    let paramsObj = require('querystring').parse(params);
    console.log(paramsObj);
    req.body = paramsObj;
})

使用express框架获取客户端post请求参数:

// 解析字符串格式的数据
app.use(express.urlencoded({extended: false}));//4.16新增的中间件

app.post('/list/test', (req, res)=>{
     console.log(req.body);
});

第三方中间件

https://github.com/senchalabs/connect#middleware

常用第三方中间件:

  1. 跨域中间件: cors
  2. 日志记录: morgan
  3. 数据校验中间件:express-validator

// middleware/vaildator/userVaildator.js
const { body } = require('express-validator')
const validate = require('./errorBack')
const { User } = require('../../model/index')
module.exports.register = validate([
  body('username')
    .notEmpty().withMessage('用户名不能为空').bail()
    .isLength({ min: 3 }).withMessage('用户名长度不能小于3').bail(),
  body('email')
    .notEmpty().withMessage('邮箱不能为空').bail()
    .isEmail().withMessage('邮箱格式不正确').bail()
    .custom(async val => {
      const emailValidate = await User.findOne({ email: val })
      if (emailValidate) {
        return Promise.reject('邮箱已被注册')
      }
    }).bail(),
  body('phone')
    .notEmpty().withMessage('手机号不能为空').bail()
    .custom(async val => {
      const phoneValidate = await User.findOne({ phone: val })
      if (phoneValidate) {
        return Promise.reject('手机号已被注册')
      }
    }).bail(),
  body('password')
    .notEmpty().withMessage('密码不能为空').bail()
    .isLength({ min: 5 }).withMessage('用户名长度不能小于5').bail(),
])


// middleware/vaildator/errorBack.js   用来统一处理错误然后返回的中间件
const { validationResult } = require('express-validator')
module.exports = validator => {
  return async (req, res, next) => {
    await Promise.all(validator.map(validate => validate.run(req)))
    const errors = validationResult(req)
    if (!errors.isEmpty()) {
      return res.status(401).json({ error: errors.array() })
    }
    next()
  }
}

// router/user.js
const express = require('express")
const router = express.Router()
const userController = require('../controller/userController')
const validator = require('../middleware/validator/userValidator')
router
.post ('/register', validator.register, usercontroller.register)
.get('/list', userController.list)
.delete('/' ‚usercontroller.delete)

module.exports = router



使用模板引擎

(dust|ejs|hbs|hjs|jade|pug|twig|vash)。默认 jade

0.app.set('views cache',false);设置模板解析是否缓存,true的话,只有第一个用户访问的时候需要解析模板,将解析过后的页面存入缓存,后面访问的用户就可以直接使用缓存,减少性能消耗

1.views,模板文件所在的目录。例如:app.set('views', './views')。这默认为views应用程序根目录中的目录。

2.view engine,要使用的模板引擎。例如,要使用ejs模板引擎:app.set('view engine', 'ejs')

3.app.engine(ext, callback)

(html模板引擎里面没有需要自己配置)

app.engine('html', require('ejs').renderFile);

在这种情况下,EJS提供了一个具有Express期望的相同签名(path, options, callback).renderFile()方法,但请注意,它在ejs.__express内部将此方法进行了别名,因此如果使用“.ejs”扩展名,则不需要执行任何操作。

错误处理

您最后定义错误处理中间件,在其他app.use()路由之后并路由呼叫; 例如:

var bodyParser = require('body-parser')
var methodOverride = require('method-override')

app.use(bodyParser.urlencoded({
  extended: true
}))
app.use(bodyParser.json())
app.use(methodOverride())
app.use(function (err, req, res, next) {
  // logic
})
var bodyParser = require('body-parser')
var methodOverride = require('method-override')

app.use(bodyParser.urlencoded({
  extended: true
}))
app.use(bodyParser.json())
app.use(methodOverride())

//打印错误
app.use(logErrors)
//判断是否是ajax请求,如果是,响应500
app.use(clientErrorHandler)
//是页面请求,告诉你一个404的页面
app.use(errorHandler)

function logErrors (err, req, res, next) {
  console.error(err.stack)
  next(err)
}

function clientErrorHandler (err, req, res, next) {
  if (req.xhr) {
    res.status(500).send({ error: 'Something failed!' })
  } else {
    next(err)
  }
}

function errorHandler (err, req, res, next) {
  res.status(500)
  res.render('error', { error: err })
}

调试Express

Mac or linux:

$ DEBUG=express:* node index.js

windows:

set DEBUG=express:* & node index.js

补充

Request 对象

request对象表示HTTP请求,包含了请求查询字符串,参数,内容,HTTP头部等属性。常见属性有:

  1. req.app:当callback为外部文件时,用req.app访问express的实例
  2. req.baseUrl:获取路由当前安装的URL路径
  3. req.body / req.cookies:获得「请求主体」/ Cookies
  4. req.fresh / req.stale:判断请求是否还「新鲜」
  5. req.hostname / req.ip:获取主机名和IP地址
  6. req.originalUrl:获取原始请求URL
  7. req.params:获取路由的parameters
  8. req.path:获取请求路径
  9. req.protocol:获取协议类型
  10. req.query:获取URL的查询参数串
  11. req.route:获取当前匹配的路由
  12. req.subdomains:获取子域名
  13. req.accpets():检查请求的Accept头的请求类型
  14. req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages
  15. req.get():获取指定的HTTP请求头
  16. req.is():判断请求头Content-Type的MIME类型
Response 对象

response对象表示HTTP响应,即在接收到请求时向客户端发送的HTTP响应数据。常见属性有:

  1. res.app:同req.app一样
  2. res.append():追加指定HTTP头
  3. res.set()在res.append()后将重置之前设置的头
  4. res.cookie(name,value ,option):设置Cookie
  5. opition: domain / expires / httpOnly / maxAge / path / secure / signed
  6. res.clearCookie():清除Cookie
  7. res.download():传送指定路径的文件
  8. res.get():返回指定的HTTP头
  9. res.json():传送JSON响应
  10. res.jsonp():传送JSONP响应
  11. res.location():只设置响应的Location HTTP头,不设置状态码或者close response
  12. res.redirect():设置响应的Location HTTP头,并且设置状态码302
  13. res.send():传送HTTP响应
  14. res.sendFile(path ,options):传送指定路径的文件 -会自动根据文件extension设定Content-Type
  15. res.set():设置HTTP头,传入object可以一次设置多个头
  16. res.status():设置HTTP状态码
  17. res.type():设置Content-Type的MIME类型
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值