zoukankan      html  css  js  c++  java
  • koa1.x获取原始body内容

       Node版本比较老,koa1.x配合koa-body-parser,默认koa-body-parser会把请求数据转成json对象,

      然而有的时候需要获取原始的内容,不要转换,看波koa-body-parser源码,找到办法。

      办法一:设置请求头Content-type值为:text/plain

      

      这样ctx.request.body就是一个字符串了.

      缺点:要毅端加东西,想到前端的懒惰,较困难,放弃。

      

      继续摸索源码,发现一个办法,代码:

    const koa = require('koa');
    const router = require('koa-router');
    const bodyParser = require('koa-body-parser');
    
    const app = new koa();
    const a = new router();
    
    function injectRawBody(rawBodyName) {
        return function* (next) {
            const ctx = this;
            let _rawBody = yield function (done) {
                let received = '';
                function onData(chunk) {
                    received += chunk;
                }
                function onEnd() {
                    ctx.req.removeListener('data', onData);
                    ctx.req.removeListener('end', onEnd);
                    done(null, received);
                }
            }
            ctx.request[rawBodyName] = _rawBody;
            yield next;
        }
    }
    
    app.use(injectRawBody('rawBody'));
    
    app.use(bodyParser();
    
    const server = require('http').createServer(app.callback());
    app.use(a.routes());
    a.post('/a', function* () {
        const ctx = this;
        const body = ctx.request.body;
        console.log("ctx.request.body:", body);
        console.log("type of ctx.request.body:", typeof body);
    
        console.log("raw body:", Buffer.concat(ctx.request.rawBody).toString());
        console.log("type of raw body:", typeof ctx.request.rawBody);
    
        yield tt.addOrCreate.apply(ctx);
        ctx.body = 'success';
    
    });
    server.listen(3000);
    

      运行,看输出,成功把原始内容挂在ctx.request.rawBody上,但ctx.request.body却成了undefined,点解?

      经过细查,发现在koa-body-parser/index.js有一句判断:

      

      因为在上一个中间件,已经耗尽了req对象的数据,所以ended就是true,那也就不会进入之后的解析了。为了一点小私,导致依赖body的功能不能用,不行不行。

      既然我放在body-parser前面不行,那我能放到后面么?像这样:

    app.use(bodyParser());
    app.use(injectRawBody('rawBody'));

      答案是不行,因为在body-parser设置了req.once,而且即使没有设置once,body-parser只有耗尽了req对象(end事件)才会继续下一个中间件,下一个中间件不能再从已经读完的ReadableStream里重新读数据。

      

      

      再细细看波源码,co、koa-body-parser、co-body、raw-body真没发现什么好方法,这几个库之间的协作太无鏠了,基本上没法hack进去。

      想过伪装一个req对象,跟ctx.req有一样的接口,让koa-body-parser里操作的是这个伪装的对象,完了之后再恢复,但没试出来,暂时放弃。

      束手无措之际,突然想起晚上在stackoverflow上看到有人问过同样的问题,回忆了一下其中一个回答,当时觉得没怎么样,现在想想真是可以用,代码:

    const koa = require('koa');
    const router = require('koa-router');
    const bodyParser = require('koa-body-parser');
    
    const app = new koa(); const a = new router(); function injectRawBody(rawBodyName) { return function* (next) { const ctx = this; let received = []; function data(chunk) { received.push(chunk); } ctx.req.on('data', data); ctx.request[rawBodyName] = received; yield next; } } app.use(injectRawBody('rawBody')); app.use(bodyParser(); const server = require('http').createServer(app.callback()); app.use(a.routes()); a.post('/a', function* () { const ctx = this; //console.log(ctx.request); const body = ctx.request.body; console.log("ctx.request.body:", body); console.log("type of ctx.request.body:", typeof body); console.log("raw body:", Buffer.concat(ctx.request.rawBody).toString()); console.log("type of raw body:", typeof ctx.request.rawBody); yield tt.addOrCreate.apply(ctx); ctx.body = 'success'; }); server.listen(3000);

      在injectRawBody中间件,绑定了data事件,接收数据。而body-parser只有在end事件发生时才会resolve,所有在injectRawBody里,获取到的是完事的数据,只是存的是buffer,使用的时候需要转换为字符串。

      优点:没有body-parser那样的限制数据大小,buffer想放多少放多少,不受node堆限制;

         简单,容易实现。

      缺点:需要转换成字符串,不会转的还可能出现乱码。

      

      

  • 相关阅读:
    java----使用socket模拟简单的http请求服务器,响应简单的文件请求操作
    Java实现的断点续传功能
    C 语言——分支和跳转
    C 语言——嵌套循环例子
    C 语言——循环
    C 语言——运算符、表达式和语句
    C 语言——字符串和格式化输入/输出
    C 语言——基础概论
    C 语言——开篇
    IDEA的安装教程
  • 原文地址:https://www.cnblogs.com/cool-fire/p/10100132.html
Copyright © 2011-2022 走看看