后端(服务端)对于前端(客户端)的来说就像是中转站,后端调用底层(操作系统)服务上层(浏览器),而他们之间的桥梁便是IO流,后端与操作系统之间的是文件IO流,与前端的便是网络IO流。这次,我们先探讨下服务端与浏览器间的业务需求。
路由解析:
经过层层网络协议的解析,我们最终从浏览器请求中获取到了相关数据。但如何处理这些数据呢,这就需要我们去解析请求的URL,并且分发相对应的处理逻辑。而URL的解析映射又分了多种方式。下面简单介绍下。
- 文件路径型:
这种解析方式就是URL路径与网站的目录的路径一致,处理起来十分简单,当我们的请求是获取一个文件,如html页面时,简单示意,如下:
const path=require('path');
const url=require('url');
const fs=require('fs');复制代码
function getFile(req,res,root) {
//获取url路径
var pathname=url.parse(req.url).pathname;
fs.readFile(path.join(root,pathname),function (err,file) {
res.end(file);
})
}复制代码
当我们需要根据URL做不同业务逻辑处理时,也是寻找对应的文件 ,如idnex.php,然后把它交给对应的脚本解析器,并传入HTTP上下文即可。记得很早之前学习PHP时,使用的Apache服务器就是文件路径型的URL处理方式。
但使用nodeJs时,由于前后端文件后缀都是.js,这样就很难判断哪个文件是nodeJs的脚本,哪个是前端脚本,所以,得用另一种解析方式。
- 手动映射型:
URL路径和文件路径是没有任何关系的,所以我们可以手动映射URL到对应的业务逻辑上,不用像文件路径一样,每个url都得对应一个文件,分发处理方面更加灵活方便。简单示例:
//业务逻辑
function todo(req,res) {
//TODO
}
//业务逻辑的集合
var routes=[];
//url映射
function use(path,action) {
routes.push([path,action]);
}
//http请求响应入口程序。
function httpServer(req,res) {
var pathname=url.parse(req.url).pathname;
//分发业务
for(var i=0;i<routes.length;i++){
var route=routes[i];
if(pathname===route[0]){
var action=route[1];
action(req,res);
return;
}
}
}
//映射一个url
use('/user/todo',todo);复制代码
是不是很简单,但我们还忽略了一点,那就是url参数,不同框架的标识不同,nodeJs的表示法是/todo/:params
,就是冒号后面的那个值表示url传递的参数,所以我们使用手动映射时,就不能直接匹配字符串了,得用正则表达式去解析url的参数出来,至于怎么弄,好像真的有点复杂,具体就不演示了,大概知道就行。当然,还有url的查询字符串,就是?a=1&b=2
这些,node的api有提供如何去获取,这里也不演示了。
手动映射的确很灵活,但项目过大的话,映射的路由也会变多过难以维护。而且查询需要费时间,当然用map
的话,时间可以缩短。所以还有另一种映射方式,无需去维护路由的映射。
- 自动映射型:
就是事先约定好某个文件中下保存了某个路由的业务逻辑,如:url路是/controls/action/123
,我们就约定好controls文件对应路径/controls
,并且用controls文件下action函数处理/controls/action
,路径剩下的便是该url的参数。简单示例:
function httpServer(req,res) {
var pathname=url.parse(req.url).pathname;
var path=pathname.split('/');
var controller=path[1];
var action=path[2];
var args=path.slice(3);
var module=require(controller);
module[action].apply(null,[req,res].concat(args));
}复制代码
是不是和文件路径映射有点像,其实原理都一样的,具体细节上的不同这里就不讲了。接下来讲下reslt。
- reslt规范:
先说下它的全称啊,Representational State Transfer(表现层状态转移),这句话具体什么意思呢,我也不是很清楚哈,大概说下我从多篇文章中以及项目使用中获得的理解吧。
reslt它是一种规范,什么规范呢,就是将http的请求方法也加入路由的过程中。如我们是通过url的路径来映射业务逻辑的,但如果遵循reslt规范,那就是判断http的请求方法后,再结合url的路径来映射对应的业务逻辑。而这就体现了reslt的设计思想,那就是通过url来设计资源,通过请求方法来定义资源的操作,通过accept请求字段来决定资源的表现形式。
嗯,希望我的理解是正确的,一段简单的示例代码:
var app={};
var routes={};
['get','put','delete','post'].forEach(function (md) {
routes[md]={};
app[md]=function (path,action) {
routes[md].push([path,action]);
}
});
function httpServer(req,res) {
var pathname=url.parse(req.url).pathname;
var method=req.method.toLowerCase();
if(routes[method]){
for(var i=0;i<routes[method].length;i++){
var route=routes[i];
if(pathname===route[0]){
var action=route[1];
action(req,res);
return;
}
}
}
}
app.get('/todo',function () {});
app.post('/todo',function () {});
app.delete('/todo',function () {});
app.put('/todo',function () {});复制代码
先写到这儿,好累啊,本来想一次全写完服务端的业务需求的,分批次来吧。