当传入的客户端 http 请求终止时终止传出的 http 请求

Terminate outgoing http requests when incoming client http request is terminated

应用概览

我有一个使用 express.js 4 模块和 node.js 核心 http 模块实现的 node.js 服务器应用程序。在高层次上,应用程序接收传入的客户端 http 消息,对其他外部 API 进行各种 http 调用(使用 http 模块),最后根据上述各种外部的响应向客户端发回响应http API 响应。

问题

我的问题是,当传入的客户端 http 请求被客户端终止时(例如,当客户端想要取消他们的请求时),我的 node.js 应用程序继续进行上述各种外部 http API来电。在这种情况下,我似乎无法找到一种方法来向我的 node.js 应用程序的其余部分发出信号,以终止其对外部 API 的各种传出 http 请求。

当客户端终止他们的请求时,express 应用程序(即 express http 服务器)收到一个 "close" 事件,我正在监听该事件。我代码中的 "close" 事件侦听器捕获此事件;但是,我似乎无法弄清楚如何向我的代码发出的 "downstream" 或 "subsequent" http 请求发出终止信号。

我的目标

当客户端终止对我的服务的传入请求时,我如何向与单个客户端传入请求相关联的所有传出 http 请求发送信号以终止?

我在下面提供了我的 node.js 应用程序的简化版本,其中包含一些内联代码注释,以帮助更清楚地说明我的问题。任何帮助或见解将不胜感激。谢谢!

附加信息

我正在使用 Apigee swagger-tools 中间件进行 api 路由。

我发现了一些类似但不完全适用于我的问题的已回答问题:

How to detect user cancels request

最佳,

克里斯

测试-app.js

// test-app.js
"use strict";

var swaggerTools = require("swagger-tools");
var app = require("express")();

// swaggerRouter configuration
// sends incoming http messages to test-controller.js
var options = {
    controllers: './controllers'
};

// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
// describes the API specification
var apiSpec = require('./test-swagger.json');

// Initialize the Swagger middleware
swaggerTools.initializeMiddleware(apiSpec, function (middleware) {
    "use strict"

    // Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
    app.use(middleware.swaggerMetadata());

    // Validate Swagger requests/responses based on test-swagger.json API specification
    app.use(middleware.swaggerValidator());

    // Route validated requests to appropriate controller, test-controller.js
    app.use(middleware.swaggerRouter(options));
});

// Run http server on port 8080
app.listen(8080, function () {
    "use strict";
    console.log("Server running on port %d", this.address().port);
})
    .on("connection", function (socket) {
        console.log("a new connection was made by an incoming client request.");
        socket.on("close", function () {
            console.log("socket connection was closed by client");
            // somehow signal to the rest of my node.js app to terminate any
            // http requests being made to external APIs, e.g. twitter api
            socket.destroy();
        });
    })

测试-controller.js

//test-controller.js
"use strict";
var http = require("https");

// only one function currently, consequently, all incoming http requests are
// routed to this function, i.e. "compile"
module.exports = {
    compile: compile
};

function compile(req, res, next) {
    var options = {
        "method": "GET",
        "hostname": "api.twitter.com",
        "path": "/1.1/statuses/mentions_timeline.json?count=2&since_id=14927799",
        "headers": {"accept": "application/json"}
    };
    // how can i terminate this request when the http.server in test-app.js receives the "close" event?
    http.request(options)
        .on("response", function(response) {
            var apiResponse = [];
            response.on("data", function (chunk) {
                apiResponse.push(chunk);
            });
            response.on("end", function () {
                apiResponse = Buffer.concat(apiResponse).toString();
                res.status(response.statusCode).set(response.headers).send(apiResponse);
            });
        })
}

在你的测试控制器的编译方法中,你应该能够做这样的事情:

var request = http.request(options, function (response) {
  res.writeHead(response.statusCode, response.headers)
  response.pipe(res, { end: true })
})
req.on('close', function(){
  request.abort()
})