首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在ERR_STREAM_PREMATURE_CLOSE中发生Node.js错误后,释放套接字的正确方法是什么?

在ERR_STREAM_PREMATURE_CLOSE中发生Node.js错误后,释放套接字的正确方法是什么?
EN

Stack Overflow用户
提问于 2021-10-26 07:59:23
回答 1查看 347关注 0票数 1

我的问题是,当我使用自定义http代理时,当响应管道发生错误时,套接字不会被释放。

看来Node.js并不是靠自己来做这个的。这就是为什么我试图通过销毁响应和底层套接字来自己发布它,但它没有工作。我尝试过的东西都没有,期望用agent.destroy()摧毁一切。这显然不是解决方案,因为像这样正确运行的套接字正在被破坏。

这就引出了我的问题。释放套接字的正确方法是什么?

模仿一个例子来再现它。

  • 你会看到插座永远被占据。

如果你打电话给http://localhost:3000/small,你会看到我期望发生的行为。也就是说套接字被释放了。

代码语言:javascript
运行
复制
const https = require("https");
const http = require("http");
const stream = require("stream");

const agent = new https.Agent({
    maxSockets: 20,
    maxFreeSockets: 10,
    keepAlive: true,
    keepAliveMsecs: 5000
});

const server = http.createServer((req, res) => {
    let url = "https://releases.ubuntu.com/20.04.3/ubuntu-20.04.3-live-server-amd64.iso?_ga=2.138549238.47332115.1635229845-1229485524.1607530765";

    if (req.url === "/small") {
        url = "https://nodejs.org/dist/v14.18.1/node-v14.18.1-x64.msi";
    }

    https.get(url, {
        agent
    }, (stream) => {
        stream.pipe(res);
    }).on("error", (e) => {
        console.error("Got error: " + e.message);
    });

    const cleanup = stream.finished(res, (error) => {
        if (error) {
            if (error.code === "ERR_STREAM_PREMATURE_CLOSE") {
                console.error("Pipeline ended non gracefully with no explicit error");

                // agent.destroy(); -- Don't want to do this!
                res.socket.destroy();
                res.destroy();
            }
        } else {
            console.info("Stream succeeded.");
        }

        cleanup();
    });

    logSockets();
});

const getSocketCountPerHost = (socketGroup) => {
    const regexp = /^:+|:+$/g;
    const sockets = agent[socketGroup];
    return Object.fromEntries(Object.entries(sockets).map(([key, value]) => [key.replace(regexp, ""), Array.isArray(value) ? value.length : value]));
}

const logSockets = () => {
    const sockets = getSocketCountPerHost("sockets");
    const freeSockets = getSocketCountPerHost("freeSockets");
    console.info("httpsAgent.sockets", sockets);
    console.info("httpsAgent.freeSockets", freeSockets);
};

server.listen(3000, () => {
    console.log("Listening on port 3000");
    setInterval(logSockets, 10_000)
});

前提条件:

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-05 06:14:34

好的,我自己去拿。关键是从https.Agent获取请求并在它过早关闭时销毁它。

代码语言:javascript
运行
复制
const clientRequest = https.get(url, {
    agent
}, (stream) => {
    stream.pipe(res);
}).on("error", (e) => {
    console.error("Got error: " + e.message);
});

const cleanup = stream.finished(res, (error) => {
    if (error) {
        if (error.code === "ERR_STREAM_PREMATURE_CLOSE") {
            console.error("Pipeline ended non gracefully with no explicit error");

            clientRequest.destroy();
        }
    } else {
        console.info("Stream succeeded.");
    }

    cleanup();
});

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69719460

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档