egg框架的使用

一、EGG框架简介和安装

1.egg.js

  • egg.js是约定(按照一套统一的约定进行应用开发 )优先于配置的一个Node.js web 框架
  • 基于koa为底层 由阿里nodejs团队封装的企业级Web应用解决方案
  • 核心设计理念:约束和规范化团队开发、帮助开发团队和开发人员降低开发和维护成本
  • 为企业级框架和应用而生 可以开发企业级的应用
  • 可以通过egg更平滑地学习后端的相关知识

2.egg安装

  1. 创建一个项目文件夹
  2. 在此目录下cmd打开命令行窗口
  3. 输入快速初始化指令 npm init egg --type=simple ; npm i
  4. 启动项目  npm run dev

注:下载过程中可能因为种种原因导致丢包,重新安装或npm i即可

3.约定规则

app/router.js:用于配置URL路由规则

app/controller/:用于解析用户的输入,处理后返回相应的结果

app/service/用于编写业务逻辑层

app/public/: 用于放置静态资源

config/config.default.js: 用于编写配置文件

config/plugin.js 用于配置需要加载的插件

二、骨架认知

1.静态资源 public

  • public文件夹内部的所有文件或文件夹都将被托管起来

2.路由Router

  • 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系
  • 即用户访问不同的路径时应该有不同的Controller去响应不同的内容

1)注册路由:

  • 当用户访问的pathname为/test时 后端就会执行controller文件夹中的home.js文件夹中的test函数
router.get('/test', controller.home.test);

2)注册的路由名与前端静态资源文件名冲突时优先访问静态资源:

  • 优先读取public的静态资源 没有就去看路由有没有注册过 也没有注册过就返回404
  • 网络请求时 后端的处理顺序:静态文件>路由匹配(按照顺序匹配)

 示例:

 

 3)相同的路由名仅匹配第一个函数, 不同的路由名可以调相同的函数

  • 相同的路由名从上至下仅匹配一次函数 不会继续匹配 即执行test1函数不会执行test2函数

4)星号路由 * 代表所有的网址都能匹配

  • 一般放在最后 否则在其之后所有的文件都会调用这个函数 不会调用原本对应的函数

3.控制器Controller

  • 负责解析用户的输入 处理后返回相应的结果
  • 可以自定义要导出模块的类继承Controller
  • 类里面的每一个方法都可以作为一个 Controller 在 Router 中引用到
  • 可以从 app.controller 根据文件名和方法名定位到这个类
  • 项目中的 Controller 类继承于 egg.Controller
  • 所有的Controller 文件都必须放在 app/controller目录下
  • 支持多级目录,访问时可以通过目录名级联访问

this的属性:

this.ctx: 当前请求的上下文 Context 对象的实例,通过它可以拿到框架封装好的处理当前请求的各种便捷属性和方法

this.ctx.body="":  body指的是数据包的响应体  相当于res.end 只执行一次 后断开网络连接

this.app: 当前应用 Application 对象的实例,通过它可以拿到框架提供的全局对象和方法

this.service:应用定义的 Service,通过它可以访问到抽象出的业务层==> this.ctx.service 

this.config:应用运行时的配置项

this.logger:logger 对象,上面有四个方法(debug,info,warn,error),分别代表打印四个不同级别的日志,使用方法和效果与 context logger 中介绍的一样,但是通过这个 logger 对象记录的日志,在日志前面会加上打印该日志的文件路径,以便快速定位日志打印位置

三、跨域

1.CORS配置

  • egg-cors 插件实现cors跨域请求

 1)下载
   npm i egg-cors

 2)开启并配置插件

 默认origin只支持一个具体的域名或*表示全部,如果想支持具体的多个指定域名需进行如下设置:

 config.cors = {
        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'
    };

 本来本地服务器是不能请求到7001服务器的数据的 但是因为配置了cors插件 允许所有的服务器访问 解决了跨域问题

2.JSONP配置

  • 如果前端的参数中有cb=fn参数(jsonp接口参数),将会返回JSONP格式的数据,否则返回JSON格式的数据 设置如下:

 通过返回的函数名判断是否存在函数,若存在就执行函数

3.代理配置

egg中的网络请求技术:

this.ctx.curl(url, option)

option常用配置:

  method:'GET/POST'

  data:{name:"karen"}//会自动字符串化

返回一个promise对象

示例:(仅以百度为示例)

index.html自己请求百度网址的数据时会跨域 报错

解决办法:

四、GET请求前后端

  • 发送的数据会显示在数据包中 参数拼接到url中 不安全 但速度快
  • egg后端接收前端GET发送的参数通过this.ctx.request.query获取

1.ajax发送GET请求

  • GET请求将参数传给后端
  • 后端返回的数据由前端的xhr对象接收 程序员用js语言来使用返回的数据

  示例:

  get.html

    <h1>ajax发送GET请求</h1>
    <input type="text" id="search">
    <button onclick="fn()">搜索</button>
    <script>   
        function fn() {
            var searchvalue=document.querySelector("#search").value
            var xhr = new XMLHttpRequest()
            var url=`http://192.168.43.17:7001/get/?keyword=${searchvalue}`
            xhr.open("GET",url)
            xhr.send()
            xhr.onreadystatechange = () => {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console.log(xhr.responseText)
                }
            }
        }
    </script>

  router.js

router.get('/get', controller.home.get);

   home.js

async get() {
    //keyword为egg后端接收到的前端GET请求发送的参数
    var keyword = this.ctx.request.query
    console.log(keyword)
    this.ctx.body = {
      info: "get接口的数据"
    }
  }

 请求结果:

 2.axios发送GET请求

  • ajax技术封装出来的 底层就是ajax 参数可以写在对象中{params}  也可以像ajax直接拼在url中
  • 后端返回的数据由前端的xhr对象接收 程序员用js语言来使用返回的数据

示例:

 get.html

    <h1>axios发送GET请求</h1>
    <input type="text" id="search">
    <button onclick="fn()">搜索</button>
    <script>
       function fn() {
            var searchvalue = document.querySelector("#search").value
            var url = `http://192.168.43.17:7001/get`
            axios(url, {params: {keyword: searchvalue}})
            .then(res=>console.log(res))

            /*参数querystring直接拼在网址中
            axios("协议://ip:port/pathname?参数querystring")
            .then(res=>console.log(res))
            */
        }
    </script>

  router.js

router.get('/get', controller.home.get);

   home.js

async get() {
    //keyword为egg后端接收到的前端GET请求发送的参数
    var keyword = this.ctx.request.query
    console.log(keyword)
    this.ctx.body = {
      info: "get接口的数据--axios"
    }
  }

 请求结果:

3.浏览器的地址栏发送GET请求

  • 只能发送GET请求
  • 接收的数据浏览器会直接读取渲染(图片、文本等)   读取/解析失败如压缩包会下载

4.a-href发送GET请求

  • 只能发送GET请求
  • 点击事件触发了默认事件才会发送GET请求(必须满足两个事件的条件)
  • 即先触发a标签的点击事件 再触发href的网络请求事件
  • 发送网络请求给href的网址,后端返回的数据,会直接读取渲染(target决定是否在新窗口渲染),读取(解析)失败如压缩包会下载

示例:

<a href="http://192.168.43.17:7001/get?name=嘻嘻嘻">a标签做网络请求</a>

请求结果: 

5.img-src发送GET请求

  • 只能发送GET请求
  • 返回的数据渲染成图片 如果是非图片编码就会“碎裂” 地址正确一定能请求到编码 只关心能否渲染

6.link-href发送GET请求

  • 只能发送GET请求 返回的数据按照加载的数据的对应功能使用

7.form发送GET请求

  • 唯一能传输文件的网络请求技术
  • 可以发送get/post/delete等请求 给action属性对应的url发送请求
  • 用户点击了(表单内部)提交按钮或者触发表单的提交事件event.submit()
  • GET请求会把form表单中的数据全部解析为url的querystring发送给后端
  • 返回的数据 同a标签 渲染/下载

 示例:

<form action="http://192.168.43.17:7001/get" method="get" target="_blank">
    //表单的input标签的name属性的值就是querystring的key值
    <input type="text" name="a">
    <input type="text" name="b">
    <button type="submit">提交</button>
</form>

 请求结果:

五、POST请求前后端

  • 不会把用户的隐私数据信息直接拼到url中发给后端
  • 用暗文发送 可以发送大量的数据给后端  响应数据相对较慢 但是较为安全
  • POST请求时 会有安全验证问题 需要关闭安全验证
  • egg后端接收POST字段和文件通过 this.ctx.request.body | this.ctx.request.files

1.ajax发送POST请求

 示例:

  post.html

    <h1>ajax发送POST请求</h1>
    账号:<input type="text" id="id"><br>
    密码:<input type="text" id="pwd">
    <button onclick="fn()">登录</button>
    <script>
            function fn(){
            var id=document.querySelector("#id").value
            var pwd=document.querySelector("#pwd").value
            var xhr = new XMLHttpRequest()
            var url="http://192.168.43.17:7001/post"
            xhr.open("POST",url,true)
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded")
            xhr.send(`id=${id}&pwd=${pwd}`)
            //send函数接收字符串querystring
            //如果是“POST”就会把这个请求的数据放在“请求数据包”-HTTPRequestMessage的请求体中的
            //如果是“GET” 不会报错 但是不会把这个数据拼接到url中发送
            xhr.onreadystatechange = () => {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console.log(xhr.responseText)
                }
            }
        }

  router.js

router.post('/post', controller.home.post);

   home.js

async post() {
    //前端POST发送给egg的参数字段
   let obj= this.ctx.request.body  
   console.log(obj) 
    this.ctx.body = {
      info: "post接口的数据",
      res:obj
    }
  }

请求结果: 

2.axios发送POST请求

1)axios.post(url,{参数字段}).then() 

示例:

    <h1>axios发送POST请求</h1>
    账号:<input type="text" id="id"><br>
    密码:<input type="text" id="pwd">
    <button onclick="fn()">登录</button>
    <script>
         function fn(){
            var id=document.querySelector("#id").value
            var pwd=document.querySelector("#pwd").value
            var url="http://192.168.43.17:7001/post"
            axios.post(url,{id:id,pwd:pwd}).then(res=>console.log(res))
         }
    </script>

 请求结果:


2)axios.post(url,参数字段/文件).then()

1.上传文件

 示例:

  postfile.html

    <h1>POST发送文件</h1>
    账号:<input type="text" id="id"><br><br>
    密码:<input type="text" id="pwd"><br><br>
    选择头像:<input type="file" id="f1" multiple><br><br>
    <button onclick="fn()">登录</button>
    <script>
        //给后端发送“大量”数据 文件 处理成表单数据
        function fn() {
            var id=document.querySelector("#id").value
            var pwd=document.querySelector("#pwd").value
            var f1=document.querySelector("#f1")
            var url="http://192.168.43.17:7001/postfile"
            var fdata = new FormData()
            fdata.append("id", id)
            fdata.append("pwd", pwd)
            fdata.append("img", f1.files[0])
            console.log(f1.files[0])
            axios.post(url,fdata).then(res=>console.log(res))
        }
    </script>

  router.js

router.post('/postfile', controller.home.postfile);

  home.js

 async postfile() {
    //前端POST发送给egg的参数字段
    let ziduan= this.ctx.request.body  
    //前端POST发送给egg的参数文件
    let f=this.ctx.request.files  //必须启用file接收文件
    console.log(ziduan,f)
    this.ctx.body = {
      info: "postfile接口的数据"
    }
  }

 请求结果:

2.移动文件

  • 用户上传的文件会保存在服务器的计算的临时路径 需要移动到项目目录中(在同一个磁盘下)

示例:

 home.js

//引入模块
const fs=require("fs")
const path=require("path")  

async postfile() {
    //前端POST发送给egg的参数字段
    let ziduan= this.ctx.request.body  
    //前端POST发送给egg的参数文件
    let f=this.ctx.request.files  //必须启用file接收文件
    console.log(ziduan,f)
   
    if(f[0]){
      let oldpath=f[0].filepath
      let fname=path.basename(oldpath)
      let newpath=__dirname+"/../public/upload"+fname  //将文件移动到upload中
      fs.renameSync(oldpath,newpath)
    }
    this.ctx.body = {
      info: "postfile接口的数据"
    }
  }

六、前端注册实例

1.前端表单验证--减轻服务器的负载--DOM操作写提示

     -邮箱验证:绑定change事件  判断value是否符合邮箱正则

     -密码验证:密码要符合格式(自己定制)两次密码一致

     -昵称验证:昵称要符合格式(自己定制)

     -身份证的验证:图片的格式和大小清晰度-预览

2.点击提交按钮时 获取用户交互的信息

3.把数据post发送给后端

4.等待后端返回数据

5.操作数据

  register.html

   <style>
        .main {
            width: 600px;
            height: 800px;
            margin: 0 auto;
            text-align: center;
            border: 1px black solid;
        }

        .idbox {
            width: 200px;
            height: 100px;
            background-image: url("img/rose.jpg");
            background-size: 200px 100px;
            margin: auto;
        }

        #idimg {
            width: 200px;
            height: 100px;
            opacity: 0;
        }

        .txbox {
            width: 100px;
            height: 100px;
            background-image: url("img/rose1.jpg");
            background-size: 200px 100px;
            margin: auto;
        }

        #tximg {
            width: 100px;
            height: 100px;
            opacity: 0;
        }
    </style>

    <div class="main">
        <h1>用户注册</h1>
        <hr>
        昵称: <input type="text" id="nc"><br><br>
        邮箱: <input type="text" id="email"><br><br>
        密码: <input type="password" id="pwd1"><br><br>
        确认密码: <input type="password" id="pwd2"><br><br>
        上传身份证: <div class="idbox"> <input type="file" id="idimg"></div>
        <span style="color: red;visibility: hidden;" id="span1">/* 只能是png、jpeg、jpg格式的图片 */</span><br>
        <span style="color: red;visibility: hidden;" id="span2">/* 小于了15kb或大于了1M */</span><br>
        选择头像:<div class="txbox"> <input type="file" id="tximg"></div>
        <br>
        <button onclick="fn()">提交</button>
    </div>
    <script>
        var arr = new Array(6).fill(true)
        //邮箱验证
        var email = document.querySelector("#email")
        email.addEventListener("change", () => {
            var reg = /^[a-zA-Z0-9]+([-_.][A-Za-zd]+)*@([a-zA-Z0-9]+[-.])+[A-Za-zd]{2,5}$/
            if (reg.test(email.value)) {
                email.style.border = "3px solid green"
                arr[0] = true
            } else {
                email.style.border = "3px solid red"
                arr[0] = false
            }
        })
        //密码验证
        var pwd1 = document.querySelector("#pwd1")
        var pwd2 = document.querySelector("#pwd2")
        pwd1.addEventListener("change", () => {
            /*1.密码必须由字母、数字组成,区分大小写
              2.密码长度为8-18位
            */
            var reg = /(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9]{8,18}$/
            if (reg.test(pwd1.value)) {
                pwd1.style.border = "3px solid green"
                arr[1] = true
            } else {
                pwd1.style.border = "3px solid red"
                arr[1] = false
            }
        })
        pwd2.addEventListener("change", () => {
            /*1.密码必须由字母、数字组成,区分大小写
              2.密码长度为8-18位
            */
            var reg = /(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9]{8,18}$/
            if (reg.test(pwd2.value) && (pwd2.value == pwd1.value)) {
                pwd1.style.border = "3px solid green"
                arr[2] = true
            } else {
                pwd2.style.border = "3px solid red"
                arr[2] = false
            }
        })
        //昵称验证 
        var nc = document.querySelector("#nc")
        nc.addEventListener("change", () => {
            var reg = /(^[\u4E00-\u9FA5·]{2,16}$)|^[a-zA-Z][a-zA-Z\s]{0,20}[a-zA-Z]$/
            if (reg.test(nc.value)) {
                nc.style.border = "3px solid green"
                arr[3] = true
            } else {
                nc.style.border = "3px solid red"
                arr[3] = false
            }
        })
        //身份证验证
        var idimg = document.querySelector("#idimg")
        idimg.addEventListener("change", () => {
            console.log(idimg.files)
            //预览
            var url1 = window.URL.createObjectURL(idimg.files[0])
            console.log(url1)
            var idbox = document.querySelector(".idbox")
            idbox.style.backgroundImage = `url(${url1})`
            //验证格式和大小
            var arr = ["image/png", "image/jpeg", "image/jpg"]
            if (arr.includes(idimg.files[0].type)) {
                span1.style.visibility = "hidden"
                arr[4] = true
            } else {
                span1.style.visibility = ""
                arr[4] = false
            }
            if (15 * 1024 > idimg.files[0].size || idimg.files[0].size > 1 * 1024 * 1024) {
                span2.style.visibility = ""
                arr[4] = false
            } else {
                span2.style.visibility = "hidden"
                arr[4] = true
            }
        })
        //头像验证
        var tximg = document.querySelector("#tximg")
        tximg.addEventListener("change", () => {
            var txbox = document.querySelector(".txbox")
            var url = window.URL.createObjectURL(tximg.files[0])
            txbox.style.backgroundImage = `url(${url})`
        })


        async function fn() {
            if (arr.includes(false)) {

            } else {
                //所有的验证都通过了才会向后端发送数据
                var fdata = new FormData()
                var nc = document.querySelector("#nc")
                var email = document.querySelector("#email")
                var pwd = document.querySelector("#pwd")
                var idimg = document.querySelector("#idimg")
                var tximg = document.querySelector("#tximg")
                fdata.append("昵称",nc.value)
                fdata.append("邮箱",email.value)
                fdata.append("密码",pwd1.value)
                fdata.append("身份证",idimg.files[0])
                fdata.append("头像",tximg.files[0])
                var re = await axios.post("/register", fdata)
                console.log(re)
            }
        }
    </script>

  register.js

async register() {
        let ziduan=this.ctx.request.body
        let f1=this.ctx.request.files
        console.log(ziduan,f1)
        this.ctx.body="注册"
    }

  router.js

router.post('/register', controller.register.register);

 请求结果:

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈哈ha~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值