管线、中间件、路由图解:
1. 请求管线
(1)request-line 1
express:服务器集成,在收到请求之后放入到请求管线中,从管线口开始逐个寻找能够匹配上url路径和请求处理的函数,找到这个能匹配的处理函数之后就用这个处理函数来解决本次请求,找不到继续...
var express = require("express");
var app = express();
app.use 方法,在请求管线中添加一个匹配条件的请求.get .post能够在请求管线中添加一个请求处理函数,这些添加的处理函数,必须要请求方式和url路径都能匹配上才能处理该请求;
next表示找不到是否要继续
app.use(function (req, res, next) {
console.log(1);
next(); //>>>login
console.log(2);
});
function isLogin(req, res, next) {
var str = "已经登录";
if (str) {
console.log("已经登录");
next(); //....
} else {
console.log("请先登录");
res.send("请先登录");
}
}
app.get("/api/login", isLogin);
// get post请求 第一个参数是接口地址,从第二个参数开始写这个接口
// 匹配的请求处理函数,可以一次性添加多个
app.get("/api/login2", isLogin, function (req, res) {
res.send("api2");
});
// 管线里面的任意一个函数,请求都要经过
app.use(function (req, res) {
res.send(404, "<h1>您访问的页面不存在</h1>");
})
app.listen(3000, function () {
console.log("Server-Running...");
});
(2)request-line 2
var express = require("express");
var app = express();
function utf8(req, res, next) {
// 设置响应头 res.set({})批量设置响应头
// Content-Type 响应头中设置编码可以解决乱码问题
res.set("Content-Type", "text/html;charset=utf-8");
console.log("设置字符编码");
next();
}
function first(req, res, next) {
console.log(" 这是第一个请求处理函数");
next();
}
function first(req, res, next) {
console.log(" 这是第一个请求处理函数");
next();
}
function second(req, res, next) {
console.log(" 这是第二个请求处理函数");
next();
}
function third(req, res, next) {
console.log(" 这是第三个请求处理函数");
next();
}
app.get("/", third, first, second, function (req, res) {
res.send("这是最后一个请求处理的函数");
});
// 中间部分可以写成一个数组
app.get("/", [utf8, first, second, third], function (req, res) {
res.send("这是最后一个请求处理的函数");
});
app.get("/hi/:age", utf8, first, second, third, function (req, res) {
var name = req.query.name;
// params 参数集合
var age = req.params.age;
console.log(req.params);
res.send(`你好${name},${age},很高兴认识你`);
/*
获取客户端数据:
1.获取url中的querystring(?后面的name=value,通过GET方式发送) req.query.name;
2.获取请求体中的数据(通过post请求发送,有多种编码方式)req.body.name
如果是urlencoded编码 需要通过body-parser模块设置
如果是multipart/form-data需要用multer模块(图像上传会讲到)
3.获取cookie中的数据 req.cookie.name
4.获取请求头中的数据
req.get('name');
5.获取url路径path中的数据
req.params.age
需要设置请求地址木事/hi/:age:目的是为了将参数放到path中
相当于将参数放到了QueryString中更容易被人和搜索引擎识别
"/hi/:age"这种url叫做友好url ,url friendly url
*/
});
app.listen(3000, function () {
console.log("Server-Running...");
});
2. 中间件
在express服务中,经常会用到一些针对于全部请求的处理函数,例如body-parser,static,session...这些都是请求处理函数都要用到的功能,(请求进行初步处理,并且进行加工,然后在传递给真正的业务逻辑接口函数),凡是满足这种定义的请求处理函数都叫做中间件;
(1)导入模块
var express = require("express");
var app = express();
var path = require("path");
var fs = require("fs");
var url = require("url");
(2)仿制express中静态文件夹的功能 1.用户只需要输入接口,不需要输入文件的绝对路径,可以读出来默认启动页的内容
function static(staticPath) {
function f(req, res, next) {
// url转成url对象
var urlObj = url.parse(req.url);
// 把url中路径和静态文件夹进行拼接>>>完整的url
var filePath = path.join(staticPath, urlObj.pathname);
// 读取文件 根据路径读取文件,带一个读取的回调
fs.lstat(filePath, function (err, s) {
if (!s) {
// 文件不存在,继续寻找请求处理管线中的其他请求处理函数
next();
} else {
// 检测当前路径读取的内容是不是文件夹目录内容
// isDirectory()检测是否为文件夹 返回布尔值
if (s.isDirectory()) {
filePath = path.join(filePath, "index.html");
}
fs.readFile(filePath, function (err, data) {
res.end(data.toString());
});
}
});
}
return f;
}
app.use(static("www"));
(3)手写body-parser
function bodyParser(req, res, next) {
// 判断是不是post请求
if (req.method == "POST") {
// 前端表单的提交 p1.name 该请求是前端的表单提交
if (req.headers["content-type"] == "application/x-www-form-urlencoded") {
// 处理数据 初始化一个buffer 0代表清空内存
var data = Buffer.alloc(0);
// on这个方法是持续性读取数据
// 回调表示此次读出来的data
req.on("data", function (d) {
// 迅雷下载
data += d;
});
// 读取完毕
req.on("end", function () {
// 转化成可以用的数据 :把接收到的请求体字符串转成对象
var obj = {};
var params = data.split("&");
params.forEach(function (el) {
var vn = el.split("=")[0]; //键
var vv = el.split("=")[1]; //值
obj[vn] = vv; //为对象附上属性和值obj
});
// 把当前贮备好的请求体对象放入到req.body里
req.body = obj;
next();
});
} else {
next();
}
} else {
next();
}
}
app.use(bodyParser);
(4) test
app.post("/api/post", function (req, res) {
res.send("这是/api/post的post接口");
console.log(req.body.username);
});
app.listen(3000, function () {
console.log("Server-Running...");
});