使用 https.request 的 POST 调用返回 408

POST call using https.request returns 408

提问人:Adithya Shetty 提问时间:11/14/2023 最后编辑:Adithya Shetty 更新时间:11/14/2023 访问量:34

问:

关于代码应该做什么的概述:

我创建了一个简单的 http 请求反向代理,使用 express 将 http/https 请求定向到本地系统,以便在本地测试应用程序(在本地环境中使用 VPN 连接到本地)。

  • Proxy 不会修改任何标头,除了它设置为的 Accept-encoding 标头外,它不按原样发送,因此我不需要使用任何包来解码传入的正文(例如 gzip)。utf-8
  • 如果启用了标志,则代理的函数是一个简单的指数函数,不适用于测试场景。backoffdo_retry

HTTP/s.request 函数实现:

/**
 * Does HTTP/HTTPS request and returns a promise.
 * @param {{}} config Config object for the request.
 * @param {Buffer|String|{}} data Data to be sent in the request.
 * @param {Number} retries Number of retries to be done if request fails defualts to request_retries variable, @see{@link {request_retries}}.
 * @returns {Promise.<{status: Number|undefined,status_message:String|undefined,headers:http.IncomingHttpHeaders,body:any}>} resolve with  response or rejects with error.
 */
const request = (config, data = null, retries = request_retries) => {
  // eslint-disable-next-line no-unused-vars
  return new Promise((resolve, reject) => {
    try {
      // get the protocol agent
      const _agent = config.protocol === "https" ? https : http;

      delete config.protocol;

      let _data = [];
      for (let i = 0; i < retries; i++) {
        const req = _agent.request(config, (res) => {
          // collect the data
          res.on("data", (chunk) => {
            _data.push(chunk);
          });

          // create the response
          res.on("end", async () => {
            let _body;

            try {
              if (res.headers["content-type"]?.includes("application/json")) {
                // remove any JSON SYNTAXERROR wrt illegal whitespace.
                // _data = _data.map((chunk) => chunk.toString().replace(/[\n\r\s\t]+/g, " "));
                _body = JSON.parse(Buffer.concat(_data).toString("utf-8"));
              }
              //parse html for content type text/html
              else if (res.headers["content-type"]?.includes("text/html")) {
                _body = Buffer.concat(_data).toString("utf-8");
              } else {
                // check if header has encoding and use that to decode the buffer.
                _body = Buffer.concat(_data).toString(res.headers["content-encoding"] ?? "utf-8");
              }
            } catch (err) {
              _body = Buffer.concat(_data).toString();
            }

            const response = {
              status: res.statusCode,
              status_message: res.statusMessage,
              headers: res.headers,
              body: _body,
            };

            // check the condition for resolving the promise.
            if (res.statusCode >= 200 && res.statusCode < 300) {
              resolve(response);
            } else if (do_retry) {
              console.warn(`[${new Date().toISOString()}][PROXY] ${config.method} request to ${config.hostname ?? config.host + config.path} failed with status ${res.statusCode}.\nretrying...`);
              //call backoff and retry the request.
              await backoff(i);
            } else if (i === retries - 1) {
              resolve(response);
            } else {
              resolve(response);
            }
          });

          // timeout handler
          res.on("timeout", () => {
            reject(new Error(`Request to ${config.hostname ?? config.host + config.path} timed out.`));
          });

          res.on("error", (err) => {
            reject(err);
          });
        });

        // send the data depending on the type of data.
        if (data && data instanceof Buffer) {
          req.write(data);
        } else if (data && typeof data === "string") {
          req.write(data, "utf-8");
        } else if (data && typeof data === "object") {
          req.write(JSON.stringify(data), "utf-8");
        }
        // close the request
        req.end();
      }
    } catch (err) {
      reject(err);
    }
  });
};

问题:

能够成功执行并调用本地系统,但调用失败。GETHEADPOST408

但是当我尝试使用邮递员“直接”进行相同的调用时,我确实获得了请求的状态。POST201

因此,我尝试使用邮递员“通过”代理进行调用,以测试标头是否丢失并导致,但在这种情况下我仍然收到相同的错误。POST408408

所以我认为请求函数没有正确实现。

整个代码在这里

JavaScript 节点 .js HTTP HTTPS

评论

1赞 Krzysztof Krzeszewski 11/14/2023
那么你有没有在邮递员那里得到 408?你在自己的问题上自相矛盾。>当我尝试使用邮递员执行相同的 POST 调用时,我确实收到 201 请求>我使用 postman 进行 POST 调用,但同样它返回了 408 错误
0赞 Adithya Shetty 11/14/2023
我的意思是说,如果我使用邮递员通过此代理进行 POST 调用,那么它会失败,使用邮递员的直接 POST 调用是成功的,更新了问题。谢谢!!!!
0赞 36ve 11/22/2023
也许值得检查 content-length 标头是否与有效负载(您发送到上游服务器的有效负载)的实际大小一致
0赞 Adithya Shetty 11/24/2023
@36ve是的,你是对的,这就是我解决它的方式,显然内容长度大于实际内容。如果你愿意,你可以回答这个问题,我可以接受。无论如何,一旦我有时间检查长度是否不匹配,我就会用其他一些细节来回答我自己的问题,比如写后调用。req.end()
0赞 36ve 11/26/2023
@AdithyaShetty当然,我会把它作为答案发布,很高兴你的问题得到了解决。

答:

1赞 36ve 11/26/2023 #1

值得检查的是,content-length 标头是否与有效负载(发送到上游服务器的有效负载)的实际大小一致。

如果数字不匹配,并且上下文长度标头大于有效负载的实际内容,则服务器可能会卡住等待永远不会传递的字节。因此,超时响应。