egg.js 是『约定优先于配置』的一个 Node.js web 框架
Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,开发人员不再是『钉子』,可以流动起来。没有约定的团队,沟通成本是非常高的,比如有人会按目录分栈而其他人按目录分功能,开发者认知不一致很容易犯错。但约定不等于扩展性差,相反 Egg 有很高的扩展性,可以按照团队的约定定制框架。使用 Loader 可以让框架根据不同环境定义默认配置,还可以覆盖 Egg 的默认约定。
Express的原班人马打造了Koa,阿里在Koa的基础之上封装出Egg,框架的命名和功能符合阿里的企业文化:egg直译为鸡蛋,轻量简洁,功能齐全,免费开源,具备一个完整生命的所有特征,为孵化伟大的互联网企业而生。
我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目(npm >=6.1.0
):
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
egg-example
├── app
│ ├── controller
│ │ └── home.js
│ └── router.js
├── config
│ └── config.default.js
└── package.json
$ npm run dev
$ open http://localhost:7001
浏览器访问: http://localhost:7001
注:如果安装指令没有报错,运行报错一般就是网络卡,防火墙等原因导致丢包了,删除整个项目文件夹,重新安装项目即可
1 app/router.js:用于配置URL路由规则;
2 app/controller/** :用于解析用户的输入,处理后返回相应的结果;
3 app/service/**: 用于编写业务逻辑层;
4 app/public/**: 用于放置静态资源;
5 config/config.{env}.js: 用于编写配置文件;
6 config/plugin.js 用于配置需要加载的插件;
路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程 [1] 。路由工作在OSI参考模型第三层——网络层的数据包转发设备。路由器通过转发数据包来实现网络互联。虽然路由器可以支持多种协议(如TCP/IP、IPX/SPX、AppleTalk等协议),但是在我国绝大多数路由器运行TCP/IP协议。路由器通常连接两个或多个由IP子网或点到点协议标识的逻辑端口,至少拥有1个物理端口。路由器根据收到数据包中的网络层地址以及路由器内部维护的路由表决定输出端口以及下一跳地址,并且重写链路层数据包头实现转发数据包。路由器通过动态维护路由表来反映当前的网络拓扑,并通过网络上其他路由器交换路由和链路信息来维护路由表。-----来自百度百科
路由指不同的地址去执行不同的分支和程序
路由是描述请求URL和具体承担执行动作的Controller的对应。说的直白点,就是用户访问不同的路径时应该有不同的Controller去响应不同的内容。
router.get('/getdata', controller.form.get);//静态路由
router.post('/pdata', controller.form.post);
//当用户访问的pathname为"/getdata"时,后端会执行controller文件夹中的home.js文件中的get函数
注册路由时,路由名不要跟静态文件名冲突,不然会优先访问静态资源
egg中路由,网络请求时,后端的处理程序:静态文件>路由匹配(按照顺序匹配)
"/*"星号路由代表所有网址都能匹配
Controller负责解析用户的输入,处理后返回响应的结果。
1.所有的Controller 文件都必须放在 app/controller目录下
2.支持多级目录,访问时可以通过目录名级联访问。
//eg:
//如果路由是:
router.get('/hello', controller.user.news)
//则控制器对应:
//在controller文件夹下有一个user文件中有一个news方法
//eg:
//如果路由是:
router.get('/hello', controller.user.home.news)
//则控制器对应:
//在controller文件夹下有一个user文件夹下有一个home文件中有一个news方法
// app/controller/home.js
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
this.ctx.body = 'Hello world';
}
}
module.exports = HomeController;
// app/router.js
module.exports = (app) => {
const { router, controller } = app;
router.get('/', controller.home.index);
};
框架提供了 egg-cors 插件来实现cors跨域请求。
//1.下载
cnpm i --save egg-cors
//2.开启插件
// config/plugin.js文件
cors:{
enable: true,
package: 'egg-cors',
}
//3.配置插件
// config/config.default.js文件
config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
}
//默认origin只支持一个域名或者*表示全部,如果想支持具体的多个指定域名可以如下设置:
config.cors = {
// origin: ['http://localhost'],
origin:function(ctx) { //设置允许来自指定域名请求
console.log(ctx);
const whiteList = ['http://www.baidu.com','http://www.hqyj.com'];
let url = ctx.request.header.origin;
if(whiteList.includes(url)){
return url;
}
return 'http://localhost' //默认允许本地请求可跨域
},
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
};
//4.使用:
//router.js文件
router.get('/cors',controller.home.cors)
//home.js文件
async cors(){
this.ctx.body={info:"这个接口可以通过跨域访问"}
}
//5. 注意:跨域前端请求时需要携带跨域凭证,不然缓存会失效
//前端网络请求时配置:
//原生ajax:
//xhr.withCredentials = true;
//axios:
axios.post(url,{},{withCredentials:true}).then((res)=>{})
//后端配置:
config.cors = {
origin: '具体的ip和端口 不能写* ',
credentials:true
}
//如果前端的参数中有cb=fn参数(jsonp接口参数),将会返回JSONP格式的数据,否则返回JSON格式的数据。
//1.配置:
// config/config.default.js文件
config.jsonp = {
callback: 'cb', // 识别 query 中的 `cb` 参数
limit: 100, // 函数名最长为 100 个字符
};
//2.写接口
// app/router.js
module.exports = app => {
const jsonp = app.jsonp();
app.router.get('/api/posts', jsonp, app.controller.posts.list);
};
也可以直接在jsonp方法中直接配置,功能一样:
//如果前端的参数中有cb=fn参数(jsonp接口参数),将会返回JSONP格式的数据,否则返回JSON格式的数据。
// app/router.js文件
module.exports = app => {
const jsonp = app.jsonp({
callback: 'cb',
limit: 100,
});
app.router.get('/api/posts', jsonp, app.controller.posts.list);
};
egg中的网络请求技术:
this.ctx.curl(url, option)
option常用配置:
method:'GET/POST'
data:{name:"karen"}//会自动字符串化
返回promise对象
//home.js文件
async cors(){
let data1=await this.ctx.curl("http://www.baidu.com",{method:"GET",data:{pwd:123}})
this.ctx.body=data1
}
1.ajax-get
GET请求传参数给后端
参数会拼接到url中,不安全,速度快
后端返回的数据,前端是xhr对象接受了,程序员用js语言来使用返回的数据
var searvalue=document.getElementById("seariput").value
var xhr=new XMLHttpRequest()
var url=`http://192.168.6.60:7001/get1?count=20&keywords=${searvalue}`
xhr.open("GET",url)
xhr.send()
xhr.onreadystatechange=()=>{
if(xhr.readyState==4&&xhr.status==200){
console.log(xhr.responseText)
}
}
2.axios-get
它是ajax技术封装出来的
后端返回的数据 前端是xhr对象接受了,程序员用js语言来使用返回的数据
var searvalue=document.getElementById("seariput").value
var url=`http://192.168.6.60:7001/get1`
axios(url,{params:{count:20,keyw:searvalue}}).then(res=>console.log(res))
function myaxios(url,obj){
// obj.params
let arr=Object.keys(obj.params)
let querystring=""
for(let i=0;i<arr.length;i++){
querystring+=arr[i]+"="+obj.params[arr[i]]
}
querystring&&(url+"?"+querystring)
// 请求它url
}
3.浏览器的地址栏[只能]发送get请求,
接受的数据会直接读取渲染,如果解析失败会下载
4.a标签的href属性也[只能]发get请求,并且是点击事件触发了默认事件才会发送get请求
发送网络请求给href的网址,后端返回的数据,接受的数据会直接读取渲染,如果解析失败会下载
5.img-src
只能发get请求 ,返回的数据渲染成图片,如果非图片编码就会"碎裂"
img.οnlοad=()=>{}
6.link-href
只能发get请求 返回的数据按照功能使用
7.form表单
发送GET/POST/DELETE等等给action属性对应的url ,发送请求
如果有"大量"的数据发给后端 用POST
<h1>post请求</h1>
账号:<input type="text" id="userid"> <br>
密码:<input type="text" id="pwd"><br>
<button onclick="fn()">登录</button>
<!-- <form action="" enctype=""></form> -->
<script>
function fn(){
console.log(6661234)
//不要把用户的隐式数据 直接拼接到url中发送给后端
//应该转为暗文发送 用POST
// 如果有"大量"的数据发给后端 用POST
var xhr=new XMLHttpRequest()
var url="http://192.168.6.60:7001/post1"
xhr.open("POST",url,true)
//这个函数接受字符串:querystring
//如果"POST"就会把这个请求的数据放在"请求数据包"-HTTPRequestMessage 的请求体中的
//如果是"GET",不会报错 但是也并不会把这个数据拼接到url中发送
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(`userid=${userid.value}&pwd=${pwd.value}`)
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.status==200){
console.log(xhr.responseText)
}
}
var url="http://192.168.6.60:7001/post1"
axios(url,{params:{userid:123,pwd:123}})
axios.get(url,{params:{userid:123,pwd:123}})
axios.post(url,{userid:123,pwd:123}).then(res=>console.log(res))
}
</script>
1.接收GET请求的数据:ctx.request.query 或者 ctx.query
2.接收POST请求的数据:ctx.request.body 而不是 ctx.body
2.1 post请求时,会有安全验证问题,简单的处理方式是关闭安全验证:
// config/config.default.js文件
//关闭csrf
config.security={
csrf:{
enable:false
}
}
2.2 post数据默认大小是100kb
如需调整可在 config/config.default.js 中覆盖框架的默认值:
// config/config.default.js文件
module.exports = {
bodyParser: {
jsonLimit: '1mb',
formLimit: '1mb',
},
};
3.接收动态路由参数
//路由:
app.get('/projects/:projectId/app/:appId',controller.form.get );
//控制器中获取:
this.ctx.params.projectId
this.ctx.params.appId
详情----快速入门 - Egg (eggjs.org)
1.前端表单验证-减轻服务器的负载-DOM操作写特效
2.点击提交按钮时 获取用户交互的信息
3.把数据POST发送给后端
4.等后端返回数据
如果返回的数据包的业务码是xxx 就操作页面xxx
如果返回的数据包的业务码是正确 就跳转到登录页面或者直接帮用户登录