目录
EGG官网,可供后面查阅:教程 - Egg
egg.js 是『约定优先于配置』的一个 Node.js web 框架
Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,开发人员不再是『钉子』,可以流动起来。没有约定的团队,沟通成本是非常高的,比如有人会按目录分栈而其他人按目录分功能,开发者认知不一致很容易犯错。但约定不等于扩展性差,相反 Egg 有很高的扩展性,可以按照团队的约定定制框架。使用 Loader 可以让框架根据不同环境定义默认配置,还可以覆盖 Egg 的默认约定。
Express的原班人马打造了Koa,阿里在Koa的基础之上封装出Egg,框架的命名和功能符合阿里的企业文化:egg直译为鸡蛋,轻量简洁,功能齐全,免费开源,具备一个完整生命的所有特征,为孵化伟大的互联网企业而生。
1、使用脚手架快速创建项目 ,小黑窗输入:npm init egg --type=simple
(上面指令输了,就会创建很多东西,比如:app config test .autod README.md等等)
2、输入指令:npm i
2.1如果卡住了,点小黑窗,按回车
2.2如果丢包了,就可以多次输入指令:npm i
2.3如果还是丢包了,就把node_modules删了,再npm i (因为package.json在,它会根据里面的信息进行下载)
2.4也可以把以前用过的文件直接压缩过后拿过来,更改相应的信息就可以了
3、启动项目:npm run dev 或者 egg-bin dev
(这个是在package.json文件里面写的 "dev":"egg-bin dev")
4、浏览器访问: http://localhost:7001
上面启动后,就需要取访问。
网址可以多种写法:
http://127.8.0.0.1:7001 或者
或者 自己的网址 : http://192.168.1.6:7001
注:如果安装指令没有报错,运行报错一般就是网络卡,防火墙等原因导致丢包了,删除整个项目文件夹,重新安装项目即可
1 app/router.js:用于配置URL路由规则;
2 app/controller/** :用于解析用户的输入,处理后返回相应的结果;
3 app/service/: 用于编写业务逻辑层;
4 app/public/: 用于放置静态资源;
5 config/config.{env}.js: 用于编写配置文件;
6 config/plugin.js 用于配置需要加载的插件;
路由器:用户把数据发送给了路由器,路由器根据用户的需求
路由:描述请求URL和具体承担执行动作的Controller的对应。
(就是用户访问不同的路径时应该有不同的Controller去响应不同的内容,就是不同的网址去执行不同的分支或者程序)
注册后端的路由:
router.get('/getdata', controller.form.get);
//静态路由,也就是调用controller文件下的form文件里的get方法router.post('/home', controller.home.ajax1);
注意点:
1、顺序是:用户网址请求(无论地址栏 还是ajax)
==> 然后去 public(静态文件)找,
==>再找路由里的(路由里面也是按照顺序匹配的)
2、注册路由时,路由名不要跟静态文件名冲突,不然会优先访问静态资源
3、如果router里面注册了两个相同的名字,但是对应执行的函数不同,最终会执行先注册的
4、如果router里面写了*==> router.get('*', controller.home.all);
意思是不管输什么都不会有404了,如果把这个放在最前面,后面写的就不会被匹配到,所以一般*写在最后一句。但是不影响静态的网址,就是public里面的。因为public优先于router.js
例子:
app/router.js
'use strict'; /** * @param {Egg.Application} app - egg application */ module.exports = app => { const { router, controller } = app; router.get('/', controller.home.fn); };
app/controller/home.js
class类里面可以写constructure,不写就有一个默认有一个空的对象 ,对象里面其中有一个功能ctx(context的缩写)
this.ctx里面有一个功能body ==>如果将this.ctx.body设置了一个值,它会自动监听到body的值发生变化,它就会调end函数,传给前端。而且在取出body值的时候,会自动转为JSON数据。所以可以赋值任何类型的值
(this.ctx就是Controller提供的功能 主要就是使用它提供的:给前端发送数据,访问插件功能)
'use strict'; //严格模式 const Controller = require('egg').Controller; //这是commonjs,不属于ES6 //以下是ES6 extends是继承,Controller是官方的功能。HomeController是继承官方的功能 class HomeController extends Controller { //HomeController这是类名,可自己取,首字母一般大写 async fn() { const { ctx } = this; ctx.body = 'hi, egg'; ctx.body = [1,2]; //这行代码不会运行了,上面一行的代码只会执行一次就断开网络连接 } } //以下是commonjs module.exports = HomeController; //导出
Controller负责解析用户的输入,处理后返回响应的结果。
1.所有的Controller 文件都必须放在 app/controller目录下
2.支持多级目录,访问时可以通过目录名级联访问。
例子: 如果router.js是: router.get('/hello', controller.user.news) 则控制器对应: 在controller文件夹下有一个user文件中有一个news方法 当用户访问的pathname为'/hello' 时 后端就会执行controller文件夹中的user.js文件中的news函数
框架提供了 egg-cors 插件来实现cors跨域请求。
1.下载
小黑窗指令 ==> cnpm i --save egg-cors
(也可以写:npm i egg-cors)cnpm就是在淘宝下载 (丢包了只能删了重新下)
npm是在国外下载,会慢一点 (丢包率稍微小一点,而且丢包了可以再继续下)
--save就是下载到依赖项,可以不写
2.开启插件
在config/plugin.js文件 (config配置,plugin插件)
cors:{ enable: true, package: 'egg-cors', }
'use strict'; /** @type Egg.EggPlugin */ module.exports = { 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', //JSONP的接口 limit: 100, }); app.router.get('/api/posts', jsonp, app.controller.posts.list); };
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、index.js中:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src='https://s1.pstatp.com/cdn/expire-1-M/axios/0.19.2/axios.js'></script> </head> <body> <h1>ajax</h1> <button onclick="fn()">请求sina</button> <script> function fn() { var url = "http://192.168.6.60:7001/sina" axios(url) .then(res => console.log(res)) } </script> </body> </html>
2、rouer.js中:
'use strict'; /** * @param {Egg.Application} app - egg application */ module.exports = app => { const { router, controller } = app; router.get('/sina', controller.home.sina); };
3、app的controller的home.js中:
'use strict'; const Controller = require('egg').Controller; class MyController extends Controller { async sina(){ //url是新浪的数据 //curl是window自带的网络工具,它集成答上下文对象中了 var url="https://api.weibo.com/2/statuses/home_timeline.json?access_token=2.00ZmCkcDlel8HDd856f9b9ccsVwsYD" let res=await this.ctx.curl(url) //this.ctx.curl(url)它的返回值是promise对象,所以用await取值 this.ctx.body=res.data.toString() //res.data是buffer类型 } } module.exports = MyController;