Egg.js 通过 $.ajax 提交表单

来源:互联网 发布:手环源码 编辑:程序博客网 时间:2024/05/01 20:42

Egg.js 是阿里开源的基于 Koa 做成的项目,号称是面向企业级的框架,听起来就有点厉害,至于到底是不是像说的那般厉害,我等小小开发者懒得关心,这个让那些牛逼哄哄的大牛吵吵去,我只想试一试这个东西到底要怎么用。

如今,Egg.js 的文档相比于刚开始放出来的时候,明显完善了许多,不过仍旧有些地方没有说明白,或许相关文档不太好找,这是所有项目的通病,不过这也没什么,既然是开源的项目,弄不明白的事情,看源码,或者在控制台等工具中一点点调试,总能弄得明白。


表单的异步提交,根据是否包含上传文件,可以分为两种。

不包含文件

以一个修改用户信息的表单作为例子,前端结构如下:

<!-- index.html --><form action="/user/update/2" method="POST">    用户名: <input id="username" name="username" type="text">    密码: <input id="newpwd" type="password"  name="newpwd">    <input id="change" type="submit" value="修改"></form>

效果如下:
这里写图片描述

前端$.ajax异步请求如下 :

// user.js$("#change").click(function(e){    // 阻止表单提交的默认事件    e.preventDefault();    let form = $(this).closest('form');    let actionUrl =  form.attr('action');    $.ajax({        url: actionUrl,        type: "POST",        data: form.serialize(),        dataType: 'json'      })      .done((results)=>{        if(results.success===1){          // 这里写请求成功后的代码        } else {          // 这里写请求失败后的代码        }      })})

上述代码很简单,就是一般的 $.ajax 请求,就不多说了。

接下来,Egg.js 服务端的处理代码:

// userController.js* update() {      let ctx = this.ctx      let body = ctx.request.body      let username = body.username      let newpwd = body.newpwd      let newInfo = {}      // 下面一句就是连接数据库修改用户信息的代码      let result = yield ctx.service.userInfo.updatePwdById(userId, username, newpwd);      if(result>0) {        return ctx.body = {          success: 1,          msg: '更新密码成功!'        }      } else {        return ctx.body = {          success: 0,          msg: '更新密码失败!'        }      }

上述代码中,因为 Egg.js 内置了 border-parser 的插件,所以可以直接使用 ctx.request.body 来接受表单post过来的数据。

关键之处在于,对于前端请求的响应,也就是这一句:

return ctx.body = {    // ...}

Koa 中,响应异步的代码可以像是这样 this.body = {},并没有return 关键字,但是 Egg.js 中,就必须要 return,否则前端就是无响应的状态,也不能随便 return 其他的东西回去,比如 return {success: 1}, 依旧没用,就得 return ctx.body={} 才行,反正我调试了那么多遍,就是这么个结果。

包含文件

这个稍微有点坑,如果没有仔细看过 其官网上文档的话,可能都不知道到底怎么回事。

先看前端代码:

<!-- index.html --><form id="change" action="/user/update/2?_csrf={{ ctx.csrf }}" method="POST">    头像: <input id="avatar" name="avatar" type="file">    昵称: <input type="text" name="nickname"></form>

与前面的表单差不多,但是需要注意的是,除了一个 类型为 fileinput 输入框之外,表单的 action 属性 url 的最后面,多加了一个参数csrf,关于 csrf 的内容,详见 Egg.js,这是关键之处,Egg.js 内置的一个安全策略,说的明白点,就是没有那个参数,类型为 post 的表单,就将被服务器拒绝接收。

当然,这里你不一定非要将 csrf 附加在表单的 action 上,还有其他的一些手段,官网上都说的很明白。

过了这个坑之后,继续往下走。

前端$.ajax异步请求如下 :

$("#change").click(function(e){    // 阻止表单提交的默认事件    e.preventDefault();    let form = $(this).closest('form');    let actionUrl =  form.attr('action');    // 我这里使用 FormData 提交表单    let formData = new FormData($('#avatar-form')[0]);    $.ajax({        url: actionUrl,        type: 'POST',        data: formData,        // 告诉jQuery不要去设置Content-Type请求头        contentType: false,        // 告诉jQuery不要去处理发送的数据        processData: false     })    .done((results)=>{        if(results.success===1){          // 这里写请求成功后的代码        } else {         // 这里写请求失败后的代码        }    })})

$.ajax 中, 其中两个属性 contentTypeprocessData 很重要,必须声明为 false

过了这个坑之后,继续往下走。

Egg.js 服务端的处理代码:

const sendToWormhole = require('stream-wormhole');const { saveFile } = require('common');...* update() {      let ctx = this.ctx      let body = ctx.request.body      let username = body.username      let newpwd = body.newpwd      let newInfo = {}      const stream = yield ctx.getFileStream();        let results = null;        try {          results = yield saveFile(stream, this.config);        } catch (err) {          // 释放掉文件流          yield sendToWormhole(stream);          throw err;        }        // 下面这句就是连接数据库,更新头像的代码        let updateUserInfo = yield ctx.service.userInfo.updateAvatarById(userId, results);        if(updateUserInfo > 0) {          return ctx.body = {            success: 1,            msg: '更新头像成功!'          }        } else {          return ctx.body = {            success: 0,            error: '更新头像失败!'          }        }}

以上代码中, 使用了 ctx.getFileStream(); 来或许前端 post 过来的文件流,如果表单中存在 input 类型为text 或者 password 的数据,则它们在 stream.fields 中,比如本例中的 昵称 数据,就可以通过 stream.fields.nickname 来获取。

读取处理文件流完毕后,必须释放内存,避免占用资源,也就是这一句:

sendToWormhole(stream);

saveFile() 方法,为真正将文件保存到服务器中的方法,如下:

// common.jslet saveFile = (stream, config)=> {  return new Promise((resolve, reject)=>{    let fileName = new Date().getTime() + '.' + stream.mimeType.split('/')[1];    let relativePath = `${config.staticServer.imagePath}/${fileName}`;    const detailPath = path.join(config.staticServer.staticPath, relativePath);    // 图片存储路径    // console.log(detailPath)    const ws = fs.createWriteStream(detailPath);    stream.pipe(ws);    ws.on('error', reject);    ws.on('end', resolve(relativePath));  })}module.exports = {  saveFile: saveFile}

其中, staticServer 是写在配置文件中的配置。

这样一来,便完成了文件的上传,文件保存路径就是上述代码输出的 detailPath

Egg.js 写了个小 Demo,有增删改查和本文的文件图片上传,地址在 douban-by-Egg

0 0
原创粉丝点击