connect强大之处在于它自带的中间件,它可以满足web开发的常见需求,比如:
中间件组件 | 介绍 |
---|---|
cookieParser() | 为后续中间件提供req.cookies和req.signedCookies |
bodyParser() | 为后续中间件提供req.body和req.files |
limit() | 基于给定字节长度限制请求主体的大小,必须用在bodyParser中间件之前 |
query() | 为后续中间件提供req.query |
logger() | 将HTTP请求的信息输出到stdout或日志文件之类的流中 |
favicon() | 响应/favicon.ico HTTP请求。通常放在中间件logger前面,这样它就不会出现在你的日志文件中了 |
methodOverride() | 可以替不能使用正确请求方法的浏览器仿造req.method,依赖于bodyParser |
vhost() | 根据指定的主机名使用给定的中间件和/或HTTP服务器实例 |
session() | 为用户设置一个HTTP会话,并提供一个可以跨越请求的持久化req.session对象。依赖于cookieParser |
basicAuth() | 为程序提供HTTP基本认证 |
csrf() | 防止HTTP表单中的跨站请求伪造攻击,依赖于session |
errorHandler() | 当出现错误时把堆栈跟踪信息返回给客户端。在开发时很实用,不过不要用在生产环境中 |
static() | 把指定目录中的文件发给HTTP客户端。跟Connect的挂载功能配合得很好 |
compress() | 用gzip压缩优化HTTP响应 |
directory() | 为HTTP客户端提供目录清单服务,基于客户端的Accept请求头提供经过优化的结果 |
7.1解析 cookie,请求主体和查询字符串的中间件
cookieParser() 解析HTTP cookie
cookieParser() 可以解析常规cookie,签名cookie和JSON cookie。
2.常规cookie
需要安装 cookie-parser这个包,其中"lalalala"是签名密钥
const connect = require('connect');
const cookieParser = require('cookie-parser');
var app = connect()
.use(cookieParser('lalalala'))
.use(function (req, res) {
console.log(req.cookies);
console.log(req.signedCookies);
res.end('hello\n');
}).listen(3000);
4.JSON cookie
JSON cookie带有前缀j 告诉connect它是一个串行化的JSON。
...
res.setHeader('set-cookie','bar=j:{"foo":"bar"}');
...
7.1.2 bodyParser() 解析请求主体
如果只是想解析x-www-form-urlencoded,仅仅在中间件使用bodyParser即可。
const bodyParser = require('body-parser');
const fs = require('fs');
var app = connect()
.use(bodyParser.urlencoded({
extended: false
}))
.use(function (req, res, next) {
console.log(req.body);
})
.listen(3000);
解析application/json需要加载json()中间件:
app.use(bodyParser.json());
其中使用了bodyParser.urlencoded函数
extended: false
:表示使用系统模块querystring来处理,也是官方推荐的extended: true
:表示使用第三方模块qs来处理- 从功能性来讲,qs比querystring要更强大,所以这里可以根据项目的实际需求来考虑
7.1.3 limit() 请求主体限制
需要限制请求主体的大小,避免大文件拖住服务器。
7.1.4 query() 查询字符串解析
需要引用connect-query解析query
下面这个小程序接收query并且发送回去
const query = require('connect-query');
var app = connect()
.use(bodyParser.urlencoded({
extended: false
}))
.use(query())
.use((req,res,next)=>{
res.end(JSON.stringify(req.query));
})
app.listen(3000);
7.2实现web程序核心功能的中间件
7.2.1 logger()记录请求
1.基本用法
直接调用logger即可。
const logger = require("connect-logger");
var app = connect()
.use(logger())
app.listen(3000);
2.定制日志格式
使用%method格式,和书中有些许差异
.use(logger({ format: `%date %method %url`}))
7.2.3 methodOverride 伪造HTTP方法
1.基本用法
X-HTTP-Method-Override是一个非标准的http头,他会根据这个头的值修改HTTP谓词
app.use(methodOverride("X-HTTP-Method-Override"))
//这样设置一个中间件
在postman这样设置methodOverride就会把请求改成PUT
const methodOverride = require('method-override');
var app = connect()
app.use(methodOverride("X-HTTP-Method-Override"))
.use(logger())
.use(edit)
.use(update)
app.listen(3000);
//上传html
function edit(req, res, next) {
if ('GET' != req.method) return next();
res.setHeader('content-type', 'text/html');
res.write('<form method="POST" action="./resource">');
res.write('<input type="text" name="user" value="Tobi"/>');
res.write('<input type="submit" value="update">');
res.write("</form>");
res.end();
}
//通过httml谓语PUT解析
function update(req, res, next) {
if ('PUT' != req.method) return next();
console.log(1);
console.log(req.body);
res.end("ok了家人们");
}
还有另一种方法:自定义函数判断
...
app.use(methodOverride(function (req, res) {
console.log(req.body);
//判断_method是否存在
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
// look in urlencoded POST bodies and delete it
var method = req.body._method
delete req.body._method
存在就返回value
return method
}
}))
...
function edit(req, res, next) {
if ('GET' != req.method) return next();
res.setHeader('content-type', 'text/html');
res.write('<form method="POST" action="./resource">');
//设置type = hidden name="_method" value = "PUT"
//就会把method设置为PUT了
res.write('<input type="hidden" name="_method" value="PUT"/>');
res.write('<input type="text" name="user" value="Tobi"/>');
res.write('<input type="submit" value="update">');
res.write("</form>");
res.end();
}
2.访问原始的req.method
console.log(req.methodOverride);