2016-11-16 20 views
2

我寫了Express中間件從請求中檢索原始主體,並在body-parser中間件之前設置它。編寫express express中間件,在body-parser之前獲取原始請求體

我定製的中間件呼籲req.setEncoding('utf8'),但是這將導致以下機身解析器錯誤:

Error: stream encoding should not be set

at readStream (/node_modules/body-parser/node_modules/raw-body/index.js:211:17) 
at getRawBody (/node_modules/body-parser/node_modules/raw-body/index.js:106:12) 
at read (/node_modules/body-parser/lib/read.js:76:3) 
at jsonParser (/node_modules/body-parser/lib/types/json.js:127:5) 

這裏是我的代碼:

var express = require('express'); 
var bodyParser = require('body-parser') 

function myMiddleware() { 
    return function(req, res, next) { 
    req.rawBody = ''; 
    req.setEncoding('utf8'); 

    req.on('data', function(chunk) { 
     req.rawBody += chunk; 
    }); 

    req.on('end', function() { 
     next(); 
    }); 
    } 
} 

var app = express(); 
app.use(myMiddleware()); 
app.use(bodyParser.json()); 

var listener = app.listen(3000, function() { 
}); 

app.get('/webhook/', function (req, res) { 
    res.sendStatus(200); 
}); 

有沒有辦法來未設置編碼?還有另一種方法可以退出原始身體,但仍然使用身體分析器後?

+1

bodyParser,然後再使用中間件? – nicovank

+0

你在'res.sendStatu(200);'中也有一個錯字。 – doublesharp

+0

你確定你需要設置編碼嗎? – doublesharp

回答

2

你打電話給next()裏面「完成」,這意味着流已經被消耗。相反,設置「數據」的處理程序,然後使用next()傳遞請求。 「完成」事件可能在bodyParser內部處理,因此執行後您可以訪問req.rawBody。如果不是這種情況,您可以添加另一箇中間件,在req.on('done')內部調用next(),以保持其餘部分不被處理,直到獲得所有數據。

// custom middleware - req, res, next must be arguments on the top level function 
function myMiddleware(req, res, next) { 
    req.rawBody = ''; 

    req.on('data', function(chunk) { 
    req.rawBody += chunk; 
    }); 

    // call next() outside of 'end' after setting 'data' handler 
    next(); 
} 

// your middleware 
app.use(myMiddleware); 

// bodyparser 
app.use(bodyParser.json()) 

// test that it worked 
function afterMiddleware(req, res, next) { 
    console.log(req.rawBody); 
    next(); 
} 

app.use(afterMiddleware); 

如果您需要訪問你可能也想看看bodyParser.raw()原體。這會將原體放入req.body,與bodyParse.json()相同,但可根據內容類型進行有條件運行 - 檢出options.type

+1

'在你的例子中,內部函數永遠不會被調用'是的,它是......函數'myMiddleware'正在返回函數,他稍後調用'app.use(myMiddleware())' – nicovank

+0

你是對的,但它不會傳入'req,res,next',因此它們不會在正確的上下文中執行 – doublesharp

+0

是的,它們是....這是一個小提琴:https://jsfiddle.net/8zn44d0c/ – nicovank

0

我推薦了不同的方法,因爲你目前的做法實際上消耗的消息,並使其無法爲身體的解析器讀取它(並有通過調用next同步涌現邊緣情況的錯誤一堆):

app.use(bodyParser.json()); 
app.use(bodyParser.text({type: '*/*'})); 

這將讀取任何application/json請求作爲JSON和其他所有文本。

如果你必須有除了文本JSON對象,我建議自己進行解析:

app.use(bodyParser.text({type: '*/*'})); 
app.use(myMiddleware); 

function myMiddleware(req, res, next) { 
    req.rawBody = req.body; 
    if(req.headers['content-type'] === 'application/json') { 
     req.body = JSON.parse(req.body); 
    } 
    next(); 
} 
+0

我認爲自己解析它將會是一條路。 – kiewic

1

事實證明,body-parser驗證選項呼叫功能時請求主體具有被讀過。該函數將該主體作爲緩衝區接收。

下面是一個例子:

var express = require('express'); 
var bodyParser = require('body-parser') 

function verifyRequest() { 
    return function(req, res, buf, encoding) { 
    // The raw body is contained in 'buf' 
    console.log(buf.toString('utf8')); 
    }; 
} 

var app = express(); 
var listener = app.listen(3000); 

// Hook 'verifyRequest' with body-parser here. 
app.use(bodyParser.json({ verify: verifyRequest })) 

app.post('/webhook/', function (req, res) { 
    res.status(200).send("done!"); 
});