【问题标题】:express.js - how to intercept response.send() / response.json()express.js - 如何拦截 response.send() / response.json()
【发布时间】:2016-02-17 09:10:04
【问题描述】:

假设我有多个地方可以拨打response.send(someData)。现在我想创建一个全局拦截器,在其中捕获所有.send 方法并对someData 进行一些更改。 express.js有什么办法吗? (钩子、监听器、拦截器……)?

【问题讨论】:

    标签: javascript node.js express


    【解决方案1】:

    是的,这是可能的。有两种方法可以做到这一点,一种是使用提供拦截的库,并能够根据特定条件运行它: https://www.npmjs.com/package/express-interceptor

    另一种选择是创建自己的中间件(用于 express),如下所示:

    function modify(req, res, next){
      res.body = "this is the modified/new response";
    
      next();
    }
    express.use(modify);
    

    【讨论】:

    • 我正在尝试为response 创建一个中间件,以便在statusCode200 时设置自定义标头,但如果我在中间件函数中运行console.log(res.statusCode),我总是会得到@987654327 @即使状态码是404401500。是否有另一种方法可以为响应获取正确的状态代码?
    • 在您发送响应之前调用中间件。它只是检查用户是否可以访问某些路由,或者不能。但是你可以将它用于其他一些东西。但是它到达路由后不会执行,尤其是在发送响应后
    【解决方案2】:

    您可以定义如下中间件(取自 answer 并进行修改)

    function modifyResponseBody(req, res, next) {
        var oldSend = res.send;
    
        res.send = function(data){
            // arguments[0] (or `data`) contains the response body
            arguments[0] = "modified : " + arguments[0];
            oldSend.apply(res, arguments);
        }
        next();
    }
    
    app.use(modifyResponseBody);
    

    【讨论】:

    • 我尝试了上述方法,它确实有效。然而 res.send 被所有 HTTP 方法(POST、PUT、DELETE)调用了两次,而 GET 只调用了一次。知道为什么 res.send 会被调用两次吗?
    • res.send=oldSend 在调用 oldSend 方法之前添加上述行可以解决上述问题。谢谢!
    • 谢谢@Jugz,解释一下如何解决这个问题会很好,谢谢。
    • 为此您必须查看internal implementation。流中的 res.send 正在内部再次被调用。因此,在初始猴子修补此方法之后,就在您调用它之前,您将其修补回原始实现。否则这会导致调用你的拦截器两次。无论如何,猴子修补并不总是一个好主意,而且上述解决方案更多是一种粗略的方法。最好使用以下使用 express-interceptor 的答案
    • 可以在自定义发送函数中使用statusCode吗?状态码将在控制器中使用 res.status(500) 设置。
    【解决方案3】:

    对于那些在谷歌上找到的人,根据最佳答案:

    app.use((req, res, next) => {
        let oldSend = res.send
        res.send = function(data) {
            console.log(data) // do something with the data
            res.send = oldSend // set function back to avoid the 'double-send'
            return res.send(data) // just call as normal with data
        }
        next()
    })
    

    【讨论】:

    • 这个工作正常。我正在使用我使用您的示例覆盖的 res.json,并添加了我想在每个响应中发送的数据。干得好
    • 感谢它对我有用! res.send = oldSend 这行是 importnat。
    【解决方案4】:

    您可以简单地使用 NODEJS 和 Express 来完成,假设您正在调用 API 并希望在发送响应之前发送修改数据。

    router.get('/id', (req,res) => {
    ... //your code here filling DATA
    
      let testData = {
        "C1": "Data1",
        "C2": "Data2",
        "yourdata": DATA
      };          
      res.send(testData);
    });
    

    【讨论】:

      【解决方案5】:

      只是想提供一个截取res.json的实际使用示例。

      当我们写快递服务器时,我们可能会根据下面的情况在每个响应中发送statusmessage

      app.post('/test', (req, res) => {
          res.json({status: 1, message: "some_error", otherData: "nothing"})
      })
      

      但是,如果我不想每次都写状态和消息怎么办?在使用res.json 时,我可以添加新函数来构建模板响应正文以发送数据。

      const messageMap = {
          0: "success",
          1: "some_error"
      }
      
      app.use((req, res, next) => {
          const originJson = res.json
          res.json = (status, jsonData) => {
              const fixedResponse = {
                  status,
                  message: messageMap[status]
              }
              originJson.call(res, {...jsonData, ...fixedResponse})
          }
          next()
      })
      

      那我只需要使用下面的函数。

      app.get("/test", (req, res) => {
          res.json(1, {otherData: 1})
      })
      
      

      您甚至可以使用构建器模式来执行此操作。

      app.use((req, res) => {
          res.buildFixedResponse = function (status)  {
              const fixedResponse = {
                  status,
                  message: messageMap[status]
              }
              res.json = function (jsonData) {
                  originJson.call(this, {...jsonData, ...fixedResponse})
              }
              return this
          }
      })
      

      然后触发函数如下。

      app.get("/test", (req, res) => {
          res.buildFixedResponse(1).json({otherData: 1})
      })
      

      【讨论】:

        【解决方案6】:

        就我而言,我必须使用带有 typicode/json-server 的中间件,并且能够获得一个不同的响应对象,而不仅仅是一个钝的 javascript 数组。

        虽然typicode/json-server 的响应类似于:

        [
         {
           ...
         }
        ]
        

        应用中间件后:

        module.exports = (req, res, next) => {
         const oldSend = res.send;
         res.send = (data) => {
          const oldData = JSON.parse(data);
          // we want to change the response only if a blunt array is sent
          // also, we do this for the old sake of not sending json arrays
          if(Object.prototype.toString.call(oldData) === '[object Array]') {
           data = {
            data: oldData
           };
          }
          res.send = oldSend;
          return res.send(data);
         };
         next();
        }
        

        响应如下:

         {
          data: [
           {
            ...
           }
          ]
         }
        

        【讨论】:

          猜你喜欢
          • 2012-03-06
          • 1970-01-01
          • 1970-01-01
          • 2019-03-21
          • 1970-01-01
          • 1970-01-01
          • 2015-11-22
          • 1970-01-01
          • 2013-06-25
          相关资源
          最近更新 更多