有关于 Transfer-Encoding:chunked 类型的响应,参见之前的文章HTTP 响应的分块传输。这里看 Koa 中如何实现。

Koa 中请求返回的处理

虽然官方文档有描述说明不建议直接调用 response.write

Bypassing Koa's response handling is not supported. Avoid using the following node properties:

  • res.statusCode
  • res.writeHead()
  • res.write()
  • res.end()

但要实现分片向客户端发送数据,必然还是得调用 Node.js Http 模块的 response.write(chunk[, encoding][, callback]) 方法,而这里的 response 就是 ctx.resctx.response

所以为什么 Koa 要说不建议直接调用上述方法操作请求的返回呢,我们来看看 Koa 内部对 response 都会做些什么默认的处理。

application.js

  handleRequest(ctx, fnMiddleware) {
const res = ctx.res;
res.statusCode = 404;
const onerror = err => ctx.onerror(err);
const handleResponse = () => respond(ctx);
onFinished(res, onerror);
return fnMiddleware(ctx).then(handleResponse).catch(onerror);
}

在应用完各种中间件后(fnMiddleware(ctx))通过 handleResponse 对请求进行一些操作,最终是在 respond 函数里。

respond 方法
function respond(ctx) {
// allow bypassing koa
if (false === ctx.respond) return; if (!ctx.writable) return; const res = ctx.res;

let body = ctx.body;

const code = ctx.status; // ignore body

if (statuses.empty[code]) {

// strip headers

ctx.body = null;

return res.end();

} if ('HEAD' == ctx.method) {

if (!res.headersSent && isJSON(body)) {

ctx.length = Buffer.byteLength(JSON.stringify(body));

}

return res.end();

} // status body

if (null == body) {

if (ctx.req.httpVersionMajor >= 2) {

body = String(code);

} else {

body = ctx.message || String(code);

}

if (!res.headersSent) {

ctx.type = 'text';

ctx.length = Buffer.byteLength(body);

}

return res.end(body);

} // responses

if (Buffer.isBuffer(body)) return res.end(body);

if ('string' == typeof body) return res.end(body);

if (body instanceof Stream) return body.pipe(res); // body: json

body = JSON.stringify(body);

if (!res.headersSent) {

ctx.length = Buffer.byteLength(body);

}

res.end(body);

}

respond 方法里会根据外部是否有设置过 ctx.body,以及不同的 header 来设置 ctx.body,最终会调用 response.end 来结束掉本次请求。

注意到如果设置了 ctx.respond = false,这个方法就直接 return 了,这是一种跳过这里处理的方式。但其实如果我们在中间件中手动调用了 ctx.res.end() 后,相当于已经提前结束掉请求了,同样也不会走 Koa 这里的处理。

所以直接在中间件中调用 ctx.res.write()ctx.res.end() 就可以实现 chunked 类型的响应,倒无须对 Koa 做额外设置。

Koa 实现 chunked 数据传输

根据上面的分析,及之前一篇关于HTTP 响应的分块传输的文章,我们得出以下 Koa 中的实现逻辑:

const Koa = require("koa");
const app = new Koa();
const PORT = 3000;
app.use((ctx, _next) => {
const res = ctx.res;
ctx.status = 200;
res.setHeader("Content-Type", "text/html");
res.write(`start<br>`);
return new Promise(resolve => {
let i = 0,
total = 5;
while (i <= total) {
(function(i) {
setTimeout(() => {
if (i === total) {
resolve();
res.end();
} else {
res.write(`${i}<br>`);
}
}, i * 1000);
})(i);
i++;
}
});
}); app.listen(PORT);

console.info(</span>server started at http://localhost:<span class="pl-s1"><span class="pl-pse">${</span><span class="pl-c1">PORT</span><span class="pl-pse">}</span></span><span class="pl-pds">);

运行效果:

Koa 中实现 chunked 响应的运行效果

如你所见,Koa 中的这个实现会在调用 ctx.res.end() 后将本来应该在页面内容中处于最顶部的内容,移动到最底部。不解。

或者通过 curl 在命令行中查看效果:

$ curl -N http://localhost:3000

命令行中接收 chunked 数据的效果

示例代码可在 wayou/koa-chunked-response 找到。

相关资源

Koa 中实现 chunked 数据传输的更多相关文章

  1. iOS中关于动态Tableview中的cell数据传输的多线程问题解决之拙见

    iOS中关于动态Tableview中的cell数据传输的多线程问题解决之拙见 (2015-12-05 12:48:20)[编辑][删除] 转载▼     首先我们先明确一下问题: 1.因为UI是在主线 ...

  2. Koa与Node.js开发实战(3)——Nunjucks模板在Koa中的应用(视频演示)

    技术架构: ​ 在Koa中应用Nunjucks,需要先把Nunjucks集成为符合Koa规格的中间件(Middleware),从本质上来讲,集成后的中间件的作用是给上下文对象绑定一个render(vi ...

  3. Koa 中 ejs 模板的使用

    ejs的基本使用 安装 koa-views 和 ejs npm install --save koa-views/cnpm install --save koa-views npm install e ...

  4. 从前端中的IOC理念理解koa中的app.use()

    忙里偷闲,打开平时关注的前端相关的网站,浏览最近最新的前端动态.佼佼者,平凡的我做不到,但还是要争取不做落后者. 前端中的IoC理念,看到这个标题就被吸引了.IoC 理念,不认识呢,点击去一看,果然没 ...

  5. koa中返回404并且刷新后才正常的解决方案

    概述 这几天学习koa2,有一些心得,记录下来,供以后开发时参考,相信对其他人也有用. 起因 这几天学习koa2,写的代码执行时有一个奇怪的bug:明明能够返回数据,却有时正常返回数据,有时偏偏给你返 ...

  6. koa 基础(十六)koa 中 session 的使用

    1.app.js /** * koa 中 session 的使用 * 1.npm install koa-session --save * 2.const session = require('koa ...

  7. koa 基础(十一)koa 中 koa-bodyparser 中间件获取表单提交的数据

    1.app.js /** * koa 中 koa-bodyparser 中间件获取表单提交的数据 * 1.npm install --save koa-bodyparser * 2.引入 const ...

  8. koa 基础(十)原生node.js 在 koa 中获取表单提交的数据

    1.app.js // 引入模块 const Koa = require('koa'); const router = require('koa-router')(); /*引入是实例化路由 推荐*/ ...

  9. Cookie、Session、JWT在koa中的应用及实现原理

    目录 Cookie 重要属性 实现原理 cookie签名实现原理 注意事项 Session 实现原理 JWT 使用方式 组成 实际应用 实现原理 前端存储方式 cookie session local ...

随机推荐

  1. Mybatis与Hibernate的对比

    Mybatis与Hibernate的对比 工作中,用了一段Hibernate与Mybatis,也在此简单的聊上几句,希望对大家有帮助. Mybatis与Hibernate不同,它不完全是一个ORM框架 ...

  2. vs2015网站部署到iis后运行调试:无法在web服务器上启动调试的问题,403已禁止

    C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files C:\Windows\Microsoft.NET\Frame ...

  3. 从柯洁对战AlphaGo,看商业智能

    [摘要]李开复赛前说,AlphaGo和李世石的人机大战是第一次,可能还有悬念,那今天的AlphaGo已经在围棋的世界中彻底甩开了人类,不再拥有任何其他的可能.并指出,AlphaGo和柯洁的比赛并非没有 ...

  4. 【sqli-labs】 less40 GET -Blind based -String -Stacked(GET型基于盲注的堆叠查询字符型注入)

    提交,页面正常,说明是')闭合的 http://192.168.136.128/sqli-labs-master/Less-40/?id=1')%23 http://192.168.136.128/s ...

  5. maven多个子项目、父项目之间的引用问题

    在项目时用到maven管理项目,在一个就项目的基础上开发新的项目:关于子项目和父项目,子项目与子项目之间的调用问题,发现自己存在不足,以下是自己查询的问题,解决了自己的疑惑. 问题 下面是一个简略的项 ...

  6. TCP协议的三次握手、四次挥手

    TCP三次握手 TCP的连接的建立需要发送三个包,一次称为三次握手(Three-way Handshake). 三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 ...

  7. Redis-RDB持久化设置

    1.如何配置RDB持久化机制redis.conf文件,也就是/etc/redis/6379.conf,去配置持久化 save 60 1000 每隔60s,如果有超过1000个key发生了变更,那么就生 ...

  8. SharePoint Designer 2013 开启新式验证(Modern Authentication)

    首先安装office 2013全家桶 再安装SharePoint Designer 2013 安装完之后,去windows检查更新,并把所有需要更新的都更新了 (更新之后我还通过KMS激活了offic ...

  9. PAT_A1072#Gas Station

    Source: PAT A1072 Gas Station (30 分) Description: A gas station has to be built at such a location t ...

  10. 使用yum update更新文件系统时不更新内核的方法

    CentOS使用yum update更新时不升级内核 cp /etc/yum.conf    /etc/yum.confbak 方法一.修改yum的配置文件 vi /etc/yum.conf  在[m ...