Open iliuyt opened 6 years ago
ctx.body在lib/context.js的第200行进行设置,可以看到ctx.body通过delegates代理了response.body。
response.body在lib/response.js中对body进行了重写getter和setter
response.body在set时,判断了返回状态status和返回内容的类型。根据返回内容的类型是否为string、buffer、stream、json来进行不同的处理.
string 类型处理时,判断是否有html标签来判断是否为html,否则返回text类型,返回时计算Content-Length
buffer 类型处理时,设置返回的Content-Length,设置返回类型为bin
stream 类型处理时,绑定在请求完成后流销毁事件,监听流的错误事件,设置返回类型为bin
json 类型处理,如果以上模型都没有匹配到,那么默认按json类型处理
在设置完ctx.body并且所有中间件执行完成后,会根据ctx.body的类型进行返回内容,代码在lib/application 的respond方法中,这里主要说一下流的处理,如果body设置的是一个流,那么会使用body.pipe(res),将ctx.body的流写入到res流中
execljs只执行流输出时候,需要调用workbook.xlsx.write方法,参数需要为一个stream,我们可以res返回流传入进去,但是使用koa框架时,传入ctx.res会出现很多坑,网上也有些使用ctx.body=stream的方法来输出流,这就需要额外声明一个转换流来让exceljs写入,让ctx.res读取,总觉得很别扭,所以索性翻开koa的源码和exceljs的源码来看一下如何实现exceljs直接写入res流中
koa默认在中间件执行完成后,根据body的类型不同做处理,在stream中采用了ctx.body.pipe(res),所以要使用koa返回只能多设置一个流。但是respond方法中有一个ctx.respond===false return的代码,那么koa是允许不执行respond,所以我们设置respond=false,进行自定义返回
在请求进来时候,默认设置了ctx.status=404,并且在设置ctx.body时,如果没有设置status,会默认设置status为200,所以如果我们没有设置ctx.status=200的话,那么默认的status为404,一样拿不到数据,所以一定要设置status为200
const Koa = require('koa'); const execl = require('exceljs'); let app = new Koa(); app.use(async ctx => { let workbook = getWorkbook(); ctx.set('Content-Type', 'application/vnd.openxmlformats'); ctx.attachment('hello.xlsx'); ctx.respond = false; ctx.status = 200; workbook.xlsx.write(ctx.res); }); app.listen(9001); function getWorkbook() { let workbook = new execl.Workbook(); let ws = workbook.addWorksheet('二货列表'); let data = { name: '二货', sex: '男', age: 22, address: '上海市长宁区' }; let vals = []; for (let key in data) { vals.push(data[ key ]); } ws.addRow(Object.keys(data)); let i = 0; do { i++; ws.addRow(vals); } while (i < 1000); return workbook; }
同时监听多个事件,如果触发了其中一个事件,释放其他所有事件
on-finished通过onFinished方法进行绑定回调,可以多次绑定, onFinished方法会在res上挂载一个单例onFinished,单例onFinished是一个回调函数,onFinished有一个属性queue用于存储通过onFinished设置的回调函数 onFinished通过监听res的end或finish方法,或者是socket的close或error方法来获取请求是否结束,请求结束后,调用单例res上的单例onFinished,清理单例onFinished,并循环调用onFinished上queue的回调方法
将多个中间件function合并,每个中间件的第二个参数为下一个要执行的中间件,中间件为一个promise
application.js->http.createServer->this.callback->this.createContext->this.handleRequest->fnMiddleware->respond
application文件中的listen中通过http.createServer创建服务,在回调方法中首先创建了ctx,然后执行中间件,最后执行respond方法结束。
创建ctx是通过Object.assign来创建新的context,request,response实例,然后绑定、代理、重写res,req的属性和方法,具体可以看context.js request.js response.js
koa源码之ctx.body
ctx.body在lib/context.js的第200行进行设置,可以看到ctx.body通过delegates代理了response.body。
response.body在lib/response.js中对body进行了重写getter和setter
response.body在set时,判断了返回状态status和返回内容的类型。根据返回内容的类型是否为string、buffer、stream、json来进行不同的处理.
string 类型处理时,判断是否有html标签来判断是否为html,否则返回text类型,返回时计算Content-Length
buffer 类型处理时,设置返回的Content-Length,设置返回类型为bin
stream 类型处理时,绑定在请求完成后流销毁事件,监听流的错误事件,设置返回类型为bin
json 类型处理,如果以上模型都没有匹配到,那么默认按json类型处理
在设置完ctx.body并且所有中间件执行完成后,会根据ctx.body的类型进行返回内容,代码在lib/application 的respond方法中,这里主要说一下流的处理,如果body设置的是一个流,那么会使用body.pipe(res),将ctx.body的流写入到res流中
koa源码之 ctx.status ctx.respond ctx.writable
在koa框架中使用exceljs执行流输出遇到的坑
execljs只执行流输出时候,需要调用workbook.xlsx.write方法,参数需要为一个stream,我们可以res返回流传入进去,但是使用koa框架时,传入ctx.res会出现很多坑,网上也有些使用ctx.body=stream的方法来输出流,这就需要额外声明一个转换流来让exceljs写入,让ctx.res读取,总觉得很别扭,所以索性翻开koa的源码和exceljs的源码来看一下如何实现exceljs直接写入res流中
坑1
坑2
代码实现
ee-first
同时监听多个事件,如果触发了其中一个事件,释放其他所有事件
on-finished
on-finished通过onFinished方法进行绑定回调,可以多次绑定, onFinished方法会在res上挂载一个单例onFinished,单例onFinished是一个回调函数,onFinished有一个属性queue用于存储通过onFinished设置的回调函数 onFinished通过监听res的end或finish方法,或者是socket的close或error方法来获取请求是否结束,请求结束后,调用单例res上的单例onFinished,清理单例onFinished,并循环调用onFinished上queue的回调方法
koa-compose
将多个中间件function合并,每个中间件的第二个参数为下一个要执行的中间件,中间件为一个promise
koa执行流程
application.js->http.createServer->this.callback->this.createContext->this.handleRequest->fnMiddleware->respond
application文件中的listen中通过http.createServer创建服务,在回调方法中首先创建了ctx,然后执行中间件,最后执行respond方法结束。
创建ctx是通过Object.assign来创建新的context,request,response实例,然后绑定、代理、重写res,req的属性和方法,具体可以看context.js request.js response.js