为什么“返回next()”会导致“错误[ERR_HTTP_HEADERS_SENT]”

时间:2019-10-24 18:19:33

标签: api express post dialogflow

我创建了一个Dialogflow聊天机器人来转换货币。我正在编写自己的Dialogflow实现,该实现调用API以根据用户请求进行对话。我不断在代码中出现“返回next()”错误,并出现“错误[ERR_HTTP_HEADERS_SENT]”错误。一旦被注释掉,我的代码就可以正常工作。

在代码中,我不断收到“ Error [ERR_HTTP_HEADERS_SENT]”错误和“ return next()”错误。一旦被注释掉,我的代码就可以正常工作。我想了解为什么。在这里输入代码

"use strict";

const express        = require("express"),
      request        = require("request"),
      app            = express()

app.use(express.json())

// POST route handler
app.post("/", (req, res, next) => {
  let { queryResult } = req.body;
  if (queryResult) {
    const { outputCurrency, amountToConvert } = queryResult.parameters;
    // Check if input currency code === output currency code
    if (amountToConvert.currency === outputCurrency) {
      const { amount } = amountToConvert;
      let responseText = `Well, ${amount} ${outputCurrency} is obviously equal to ${amount} ${outputCurrency}!`;
      let respObj = {
        fulfillmentText: responseText
      };
      res.json(respObj); //send back object to Dialogflow
    } else {
      // Query the currencyconverter API to fetch rates and create a response
      convertCurrency(amountToConvert, outputCurrency, (error, result) => {
        if (!error && result) {
          let respObj = {
            fulfillmentText: result  //send back response to Dialogflow
          };
          res.json(respObj);          
        }
      });
    }
  }
  //return next();   //with this line running, I keep getting 
                    //Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
});

//function to call API and convert currency
const convertCurrency = (amountToConvert, outputCurrency, cb) => {
    const { amount, currency } = amountToConvert;
    const reqObj = //assemble the api request
    { 
      url: "https://free.currconv.com/api/v7/convert",
      qs: {        
        q: `${currency}_${outputCurrency}`,
        compact: "ultra",
        apiKey: "f0a68e5b725035985796"
      },
      method: "GET",
      json: true
    }
    return request( 
      reqObj,
      (error, response, body) => {   
        if (!error && response.statusCode === 200) {
          let computedValue = Math.round(
            body[`${currency}_${outputCurrency}`] * amount
          );
          cb( //this is the message i send back to Dialogflow (DF)
            null,
            `${amount} ${currency} converts to about ${outputCurrency} ${computedValue} as per current rates!`
          );
        } else {
          cb(error, null);
        }
      }
    );
  };

app.listen(3000, () =>{
  console.log("server started")
})

1 个答案:

答案 0 :(得分:1)

在发送响应的代码路径中,您不想同时调用next()。您的代码正在执行此操作,这导致沿线的其他路由也尝试发送响应,从而导致Express内部出现“标头已发送”消息。

呼叫next()将继续路由到其他路由,并且发送响应后,您就不想这样做了。您的代码需要为通过路由处理程序的每条可能路径发送一个且只有一个响应。此外,由于此路由处理程序正在“处理”路由,因此没有理由在通过代码的任何路径上调用next()。相反,通过代码的所有可能路径必须发送成功的响应或错误的响应,以及一个且只有一个响应。

这是尝试清除代码中的所有可能路径并添加适当的错误响应的一种尝试:

// POST route handler
app.post("/", (req, res, next) => {
  let { queryResult } = req.body;
  if (!queryResult) {
    res.status(400).json({error: "Missing data in post"})
  } else {
    const { outputCurrency, amountToConvert } = queryResult.parameters;
    // Check if input currency code === output currency code
    if (amountToConvert.currency === outputCurrency) {
      const { amount } = amountToConvert;
      let responseText = `Well, ${amount} ${outputCurrency} is obviously equal to ${amount} ${outputCurrency}!`;
      res.json({fulfillmentText: responseText}); //send back object to Dialogflow
    } else {
      // Query the currencyconverter API to fetch rates and create a response
      convertCurrency(amountToConvert, outputCurrency, (error, result) => {
        if (error || !result) {
          console.log(error);
          res.status(500).json({error: "currency conversion failure"});
        } else  {
          res.json({fulfillmentText: result});   //send back response to Dialogflow
        }
      });
    }
  }
});