本文来源于 哲玄前端(抖音ID:44622831736)大前端全栈实践课程 ,记录里程碑1的学习笔记。课程内容非常值得,刚入行的小白也可以听懂,哲哥用js语言带你快速了解后端的世界!强推。
介绍
elpis-core 是参考 Egg.js "约定大于配置" 理念实现的服务端框架。采用模块化设计,将项目划分为7大模块,核心部分有详细说明。各模块间划分清晰,便于专注模块的开发。
核心部分:
将项目文件通过loader解析挂载到eplis-core上。
在elpis-core\index.js通过执行elpis-core\loader中的文件,实现功能挂载app对象上,作为项目启动的准备工作。
各loader加载顺序以及作用如下:
- middleware loader 加载所有中间件到 app.middlewares
- router-schema loader 加载接口校验规则到 app.routerSchema,验证请求参数是否合法,提供给中间件使用
- controller loader 加载所有控制器到 app.controller,决定请求怎么处理
- service loader 加载所有服务到 app.service,处理具体业务逻辑
- config loader 加载配置文件到 app.config
- extend loader 加载扩展功能,直接挂载到 app
- 全局中间件 (app/middleware.js) 执行用户自定义的中间件
- router loader 注册所有路由规则,匹配URL并调用控制器处理
应用:
- 走通浏览器展示页面(借助koa-nunjuck渲染) (/view/)
需要渲染的文件放在app/public/output中 路由router(配置好路径)->controller->service
请求所经过的路径如下:
- 在middeware中注册koa-nunjuck,设置路径为app/public
- 用户请求页面,进入router (http://localhost:8080/view/page1) 其中 router.get('/view/:page',viewController.renderPage.bind(viewController)), :page获取到用户访问路径中的第二参数 page1,调用viewController的renderPage方法渲染页面。
- renderPage中 await ctx.render(
output/entry.${ctx.params.page},{}); 根据注册koa-nunjuck配置的基础路径app/public 拼接上对应的 output/entry.page1 ,找到对应的资源(app/public/output/entry.page1)渲染。 - render中第二个参数可以作为数据注入使用,需要注入的地方使用模板{{}},如
参数中配置该对象{name:'xxx',age:18} 页面渲染{{name}} ,{{age}} 通常不直接渲染上页面,通过input配置id和value,并且隐藏input,把需要的属性挂载到window的变量上
async renderPage(ctx){
await ctx.render(`output/entry.${ctx.params.page}`,{
name:app.options?.name,
env:app.env.get(),
options:JSON.stringify(app.options)
});
}
<body>
<h1>
Page1
<input type="text" id="env" value="{{env}}" style="display: none;">
<input type="text" id="options" value="{{options}}" style="display: none;">
</h1>
</body>
<script>
try{
window.env= document.getElementById('env').value;
const options= document.getElementById('options').value;
window.options= JSON.parse(options);
}catch(e){
console.log(e);
}
</script>
-
api请求(/api/)
- 页面请求( /api/project/list )
- 经过 apiSignVerify 签名验证中间件,校验请求头中是否含正确的签名,以及前后请求的时间是否超时。若不符合中间件层就拦截返回。
- 再经过apiParamsVerify 参数校验,在router-schema中配置get/post/put...对应的校验规则,在中间件中获取到配置的校验规则,对api的body,query,params,headers作校验。不符合则拦截。
- 进入router进行路由分发,调用对应controller的对应方法,controller调用对应service获取所请求的数据,再由controller层返回请求结果。
-
基础设施
- 添加koaStatic中间件,便于页面静态资源的访问。
- 添加logger日志工具(extend),便于调整不同环境的日志输出位置,本地使用console,测试和开发使用log4js将日志落盘便于排除。统一调用app.logger.info / app.logger.error 进行日志打印。
- 添加koa-bodyparser中间件,便于controller中获取请求的body参数。
- 添加errorHandle中间件,使用try-catch对全局的异常进行捕获。请求空页面使其重定向用户自定义地址;api异常则统一返回错误内容。
- controller和service实现基类,抽取共同的方法,需要实现的时候继承基类进行开发。这也是controller和service设置成类的原因。
补充理解:
-
Koa-router 会自动处理 ctx 的传递:
- 当请求 /view/xxx 进来时,(/view/:page)
- Koa-router 会调用 viewController.renderPage(ctx, next)
- ctx 是 Koa 自动创建的上下文对象, next调用下一个中间件
- ctx.params.page 就是 URL 中的 xxx
-
node.js的全局对象
- process 进程信息
- console 控制台输出
- buffer 二进制数据处理
- setTimeOut/setInterval 定时器
- __dirname 当前文件所在目录
- __filename 当前文件完整路径
-
koa洋葱圈模型
- 接口和页面请求先 进入到中间件,再通过路由分发进入对应的controller->service进行处理 , 最后离开中间件进行响应返回。
- 中间件中含ctx,next。首次进入会执行next之前的代码,离开时执行next之后的代码,可以理解成多中断处理
-
ctx涉及到的属性解释(这次请求的全部上下文,从用户发请求到服务器响应,所有数据都装在里面)
- Request http请求中的 query,body,headers 访问如下requset.query ...
- Params 字段取决路由中的配置,如/view/:page/:id ->ctx.params.page ,ctx.params.id
- Path 本次请求的路径,如/api/project/list
- Method 请求方法 put,get,post,delete
- Body 返回的主体内容,包括{code,data,metadata}
- Status http请求返回的状态码
- Redirect() 重定向位置
- 可能用到ip,cookies,session
-
重定向301,302,303
- 重定向过程: 请求返回3xx状态码,在location设置需要跳转的位置,页面收到该状态码的响应后再次发送请求,去跳转location指定的地址。
- 301,永久重定向,浏览器缓存了重定向的地址,后续请求无论是否正常都直接跳转重定向的地址。
- 302,临时重定向,每次都询问一次需要跳转的地址,若接口正常则无需继续跳转。
- 303,临时重定向,要求跳转请求用GET请求,其余与302相同。