egg框架
什么是Egg.js?
Egg.js 是为企业级框架和应用而生的,希望由 Egg.js 孕育出更多上层框架,帮助开发团队和开发人员降低开发和维护成本
注意:Egg.js 缩写为 Egg,我们平常所说的egg就是egg.js
Egg 的插件机制有很高的可扩展性,一个插件只做一件事,Egg 通过框架聚合这些插件,并根据自己的业务场景定制配置,这样应用的开发成本就变得很低
Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,但约定不等于扩展性差,相反 Egg 有很高的扩展性,可以按照团队的约定定制框架。使用 Loader 可以让框架根据不同环境定义默认配置,还可以覆盖 Egg 的默认约定
egg的特性
- 提供基于 Egg 定制上层框架的能力
- 高度可扩展的插件机制
- 内置多进程管理
- 基于 Koa 开发,性能优异
- 框架稳定,测试覆盖率高
- 渐进式开发
egg环境的安装
推荐直接使用脚手架,只需几条简单指令,即可快速生成项目,免去了许多自己安装的麻烦,也不会出现因为安装失误而导致的环境集成失败
先建一个目录,用于安装环境的
mkdir egg-example && cd egg-example
快速安装egg框架,一般我们都直接用simple,就不需要自己去写骨架了
npm init egg --type=simple
除了simple还有一下几种安装的可选项
simple 简单 egg 应用程序骨架
empty 空的 egg 应用程序骨架
plugin egg plugin 骨架
framework egg framework 骨架
安装所需的模块,会根据 package.json 文件里的信息去自动安装我们需要的所有模块
npm i
安装完成后就可以启动项目了,启动都是在小黑窗里面启动哦
启动命令:npm run dev
然后去浏览器访问: http://localhost:7001,测试一下安装的环境有没有什么问题
注意:如果安装指令没有报错,运行报错一般就是网络卡了绘制防火墙没关又或者你电脑里安装的一些安全软件阻止了一些文件的运行等等原因导致丢失了数据包,遇到这种情况就直接删除整个项目文件夹,重新安装项目即可
egg的约定规则
- app/router.js:用于配置URL路由规则
- app/controller/ :用于解析用户的输入,处理后返回相应的结果
- app/service/: 用于编写业务逻辑层
- app/public/: 用于放置静态资源
- config/config.{env}.js: 用于编写配置文件
- config/plugin.js 用于配置需要加载的插件
路由
Router 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系, 框架约定了 app/router.js 文件用于统一所有路由规则
通过统一的配置,我们可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突,集中在一起我们可以更方便的来查看全局的路由规则
路由:指不同的网址去执行不同的分支或者程序
定义路由的实例
在app/router.js 里面定义 URL 路由规则
module.exports = app => {
const { router, controller } = app;
router.get('/home', controller.user.info);
};
app/controller 目录下面实现 Controller
class UserController extends Controller {
async info() {
const { ctx } = this;
ctx.body = '<h1>hi, user</h1>';
}
}
执行结果
Router 详细定义说明
下面是路由的完整定义,参数可以根据场景的不同,可以自由选择:
router.verb('path-match', app.controller.action);
router.verb('router-name', 'path-match', app.controller.action);
router.verb('path-match', middleware1, ..., middlewareN, app.controller.action);
router.verb('router-name', 'path-match', middleware1, ..., middlewareN, app.controller.action);
路由完整定义主要包括5个主要部分:
- verb - 用户触发动作,支持 get,post 等所有 HTTP 方法。
- router-name 给路由设定一个别名,可以通过 Helper 提供的辅助函数 pathFor 和 urlFor 来生成 URL。(可选)
- path-match - 路由 URL 路径。
- middleware1 - 在 Router 里面可以配置多个 Middleware。(可选)
- controller - 指定路由映射到的具体的 controller 上,controller 可以有两种写法:app.controller.user.fetch - 直接指定一个具体的 controller’user.fetch’
注意:注册路由时 路由名不要跟静态文件名冲突 不然会优先访问静态资源
router.get(“/*”,controller.home.all); 当使用 *号时,表示与所以的网址适配,因此这个应该写在最后一个位置,不然随便输入什么就与之适配了,就不会匹配到对应的网址请求来的数据了
注册了两个相同的路由,只能访问到第一个
控制器Controller
Controller 负责解析用户的输入,处理后返回相应的结果
- 在 RESTful 接口中,Controller 接受用户的参数,从数据库中查找内容返回给用户或者将用户的请求更新到数据库中。
- 在 HTML 页面请求中,Controller 根据用户访问不同的 URL,渲染不同的模板得到 HTML 返回给用户。
- 在代理服务器中,Controller 将用户的请求转发到其他服务器上,并将其他服务器的处理结果返回给用户。
Controller 层主要对用户的请求参数进行处理(校验、转换),然后调用对应的 service 方法处理业务,得到业务结果后封装并返回:
- 获取用户通过 HTTP 传递过来的请求参数。
- 校验、组装参数。
- 调用 Service 进行业务处理,必要时处理转换 Service 的返回结果,让它适应用户的需求。
- 通过 HTTP 将结果响应给用户。
所有的Controller 文件都必须放在 app/controller目录下
支持多级目录,访问时可以通过目录名级联访问
实例
module.exports = app => {
const {router,controller } = app;
router.get('/ajax1/fn', controller.home.ajax1);
router.get('/caradd', controller.car.add);
}
执行结果
CORS配置
浏览器判断跨域为简单请求时候,会在Request Header中添加 Origin 字段 , 它表示我们的请求源,CORS服务端会将该字段作为跨源标志
CORS接收到此次请求后 , 首先会判断Origin是否在允许源(由服务端决定)范围之内,如果验证通过,服务端会在Response Header 添加 Access-Control-Allow-Origin、Access-Control-Allow-Credentials等字段
浏览器收到Respnose后会判断自己的源是否存在 Access-Control-Allow-Origin允许源中,如果不存在,会抛出“同源检测异常”
当跨域为简单请求时只需要CORS服务端在接受到携带Origin字段的跨域请求后,在response header中添加Access-Control-Allow-Origin等字段给浏览器做同源判断就可以了
但我们使用框架,这些底层代码就会被封装起来,我们也看不到底层代码,只要了解他们是怎么回事,知道在框架中该怎么用axios,jsonp和代理服务就可以了
实例
html文件
axios的引入可以自己去官网下载也可以去引入,在上一篇文章里已经讲过,不会可以去看看
<h1>ajax</h1>
<button onclick="fn()">请求</button>
<script src='https://s1.pstatp.com/cdn/expire-1-M/axios/0.19.2/axios.js'></script>
<script>
function fn(){
axios("http://192.168.43.132:7001/ajax1")
.then(res=>console.log(res))
}
</script>
router.js文件
module.exports = app => {
const { router, controller } = app;
router.get('/ajax1', controller.home.ajax1);
};
controller/home.js 文件
class MyController extends Controller {
async ajax1(){
this.ctx.body={info:"ajax接口的数据",code:123456}
}
}
module.exports = MyController;
执行结果
JSONP配置
实例
router.js文件
module.exports = app => {
router.get('/jsonp',app.jsonp(), controller.home.jsonp);
};
controller/home.js 文件
class MyController extends Controller {
async jsonp() {
this.ctx.body = {
info: "json接口的数据",
code: 20001
}
}
}
module.exports = MyController;
执行结果
代理配置
代理服务:我们自己前端直接请求别的服务的数据会有跨域限制,所以我们自己的前端请求自己的后端服务器,然后后端的服务器在用require请求别的服务器,别的服务器把数据传给我们的后端,我们的后端再把数据传给我们自己的前端,前端在操作数据写入页面,我们的后端服务器就叫做代理服务器
实例
router.js文件
module.exports = app => {
router.get('/baidu', controller.home.baidu);
};
controller/home.js 文件
class MyController extends Controller {
async baidu(){
var url = "http://www.baidu.com";
let res=await this.ctx.curl(url)
this.ctx.body=res.data
}
}
module.exports = MyController;
执行结果
get请求
ajax-get请求
GET请求传参数给后端
参数会拼接到url中
它的特点是速度快,但是不安全
后端返回的数据 前端是xhr对象接受了,并用js语言来使用返回数据
实例
html文件
<h1>get请求</h1>
<input type="text" id="seariput">
<button onclick="fn()">搜索</button>
<script>
function fn() {
var searvalue=document.getElementById("seariput").value
var xhr=new XMLHttpRequest()
var url=`http://192.168.43.132: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)
}
}
}
</script>
router.js文件
module.exports = app => {
router.get('/get1', controller.home.get1);
};
controller/home.js 文件
class MyController extends Controller {
async get1() {
var k = this.ctx.request.query
console.log(k)
this.ctx.body = {
info: "get1接口的数据"
}
}
}
module.exports = MyController;
执行结果
axios-get请求
实例
html文件
<h1>get请求</h1>
<input type="text" id="seariput">
<button onclick="fn()">搜索</button>
<script src='https://s1.pstatp.com/cdn/expire-1-M/axios/0.19.2/axios.js'></script>
<script>
function fn() {
var searvalue=document.getElementById("seariput").value
var url=`http://192.168.43.132:7001/get1`
axios(url,{params:{count:30,keyw:searvalue}})
.then(res=>console.log(res))
}
</script>
router.js文件
module.exports = app => {
router.get('/get1', controller.home.get1);
};
controller/home.js 文件
class MyController extends Controller {
async get1() {
var k = this.ctx.request.query
console.log(k)
this.ctx.body = {
info: "get1接口的数据"
}
}
}
module.exports = MyController;
执行结果
form-get请求
实例
html文件
<form method="GET" action="http://192.168.43.132:7001/login" target="_blank">
<input type="text" name="aaa"><br>
<input type="text" name="bbb"><br>
<input type="submit" value="login"><br>
</form>
router.js文件
module.exports = app => {
router.get("/login",controller.home.login)
};
controller/home.js 文件
class MyController extends Controller {
async login(){
var k = this.ctx.request.query
console.log(k)
this.ctx.body="登陆成功"
}
}
module.exports = MyController;
执行结果
那些地方只能做get请求呢?
- 浏览器的地址栏只能发送get请求,接受的数据会直接读取渲染,如果解析失败会下载
- a标签的href属性也只能发get请求,并且是点击事件触发了默认事件才会发送get请求, 发送网络请求给href的网址,后端返回数据,接受的数据会直接读取渲染,如果解析失败会下载
- .img-src,只能发get请求 返回的数据渲染成图片 如果非图片编码就会"碎裂"
- .link-href,只能发get请求 返回的数据按照功能使用
- form表单,发送GET/POST/DELETE等等给action属性对应的url 发送请求
1.用户点击了提交按钮或者触发表单的提交事件
2.get请求会把form中的数据全部解析为url的querystring
3.返回的数据 同a标签
post请求
当用户有隐私数据需要传输的时候,我们应该用POST请求,因为post请求在传输过程中会进行加密处理,不会向get一样直接拼接到地址栏中,更加安全,但是传输速度没有get快
如果有"大量"的数据发给后端 也要用POST请求
实例
html文件
<h1>post请求</h1>
账号:<input type="text" id="userid"> <br>
密码:<input type="text" id="pwd"><br>
<button onclick="fn()">登录</button>
<script>
function fn(){
var userid = document.querySelector("#userid");
var pwd = document.querySelector("#pwd");
var xhr=new XMLHttpRequest()
var url="http://192.168.43.132:7001/post1"
xhr.open("POST",url,true)
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)
}
}
}
</script>
router.js文件
module.exports = app => {
router.post('/post1', controller.home.post1);
};
controller/home.js 文件
class MyController extends Controller {
async post1() {
let obj=this.ctx.request.body
let query=this.ctx.request.query
console.log(obj,query)
this.ctx.body={info:"登录成功",res:obj}
}
}
module.exports = MyController;