chimurai / http-proxy-middleware

:zap: The one-liner node.js http-proxy middleware for connect, express, next.js and more
MIT License
10.68k stars 826 forks source link

HttpProxyMiddleware [ERR_STREAM_WRITE_AFTER_END] when using agent #1021

Open twinkle77 opened 1 month ago

twinkle77 commented 1 month ago

Checks

Describe the bug (be clear and concise)

I'm using HttpProxyMiddleware, with those options:

export const httpProxy = createProxyMiddleware({
  agent: new HttpsProxyAgent('http://127.0.01:10701'),
  pathRewrite: {
    '/tob_gateway': '',
  },
  router: () => {
    return 'http://URL_ADDRESSxxxxx';
  },
  secure: false,
  changeOrigin: true,
  on: {
    proxyReq: (proxyReq, req) => {
      const requestBody = (req as unknown as BodyParserLikeRequest)?.body;

      if (!requestBody) {
        return;
      }

      const writeBody = (bodyData: string) => {
        proxyReq.write(bodyData);
      };

      const contentType = proxyReq.getHeader('Content-Type') as string;
      if (
        contentType &&
        (contentType.includes('application/json') ||
          contentType.includes('+json'))
      ) {
        writeBody(JSON.stringify(requestBody));
      }

      if (
        contentType &&
        contentType.includes('application/x-www-form-urlencoded')
      ) {
        writeBody(querystring.stringify(requestBody));
      }
    },
  },
});

I know that the body is empty since I read the stream with express.raw which using bodyParser behind the scenes, but how can I write it back again before its sent? I cant make any request changes on 'onProxyReq', since I get errors like the above, and if I try to change any headers I get [ERR_HTTP_HEADERS_SENT]

I want to write the request body back before I send it to the server

Step-by-step reproduction instructions

1. ...
2. ...

Expected behavior (be clear and concise)

i can to write body when proxyReq event is triggered( use agent option)

How is http-proxy-middleware used in your project?

as a http proxy

What http-proxy-middleware configuration are you using?

export const httpProxy = createProxyMiddleware({
  agent: new HttpsProxyAgent('http://127.0.01:10701'),
  pathRewrite: {
    '/tob_gateway': '',
  },
  router: () => {
    return 'http://URL_ADDRESSxxxxx';
  },
  secure: false,
  changeOrigin: true,
  on: {
    proxyReq: (proxyReq, req) => {
      const requestBody = (req as unknown as BodyParserLikeRequest)?.body;

      if (!requestBody) {
        return;
      }

      const writeBody = (bodyData: string) => {
        proxyReq.write(bodyData);
      };

      const contentType = proxyReq.getHeader('Content-Type') as string;
      if (
        contentType &&
        (contentType.includes('application/json') ||
          contentType.includes('+json'))
      ) {
        writeBody(JSON.stringify(requestBody));
      }

      if (
        contentType &&
        contentType.includes('application/x-www-form-urlencoded')
      ) {
        writeBody(querystring.stringify(requestBody));
      }
    },
  },
});

What OS/version and node/version are you seeing the problem?

mac: 14.4.1
node: v20.15.0

Additional context (optional)

No response

twinkle77 commented 1 month ago

https://stackoverflow.com/questions/78429842/httpproxymiddleware-err-stream-write-after-end-when-using-agent

I found the same problem onstackoverflow

wll8 commented 2 weeks ago

This code fails in the following circumstances:


const express = require(`express`)
const { createProxyMiddleware, fixRequestBody } = require(`http-proxy-middleware`)

const app = express()

const defaultConfig = {
  ws: true,
  secure: false,
  changeOrigin: true,
  onProxyReq: (proxyReq, req, res) => {
    // https://github.com/chimurai/http-proxy-middleware/pull/492
    fixRequestBody(proxyReq, req)
  },
  logLevel: `silent`,
  pathRewrite: { '^/amap/': `https://restapi.amap.com/` },
  // proxyTimeout: 60 * 1000,
  // timeout: 60 * 1000,
}

app.use(`/amap/`, createProxyMiddleware({ ...defaultConfig, target: `https://restapi.amap.com/`}))
app.listen(8840)

Visit the following link:

:8840/amap/v3/geocode/regeo?key=******&location=37.09024%2C-95.712891&extensions=all&appname=*****

An error occurs under Linux:

events.js:292
      throw er; // Unhandled 'error' event
      ^

Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    at writeAfterEnd (_http_outgoing.js:668:15)
    at write_ (_http_outgoing.js:680:5)
    at ServerResponse.write (_http_outgoing.js:661:15)
    at IncomingMessage.ondata (internal/streams/readable.js:719:22)
    at IncomingMessage.emit (events.js:315:20)
    at IncomingMessage.Readable.read (internal/streams/readable.js:519:10)
    at flow (internal/streams/readable.js:992:34)
    at resume_ (internal/streams/readable.js:973:3)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)
Emitted 'error' event on ServerResponse instance at:
    at writeAfterEndNT (_http_outgoing.js:727:7)
    at processTicksAndRejections (internal/process/task_queues.js:81:21) {
  code: 'ERR_STREAM_WRITE_AFTER_END'
}

Same code and same version number, no problem under Windows.


If you use http-proxy-middleware@3.0.0 and replace with the following code, the problem can be solved.


const express = require(`express`)
const { createProxyMiddleware, legacyCreateProxyMiddleware,  fixRequestBody } = require(`http-proxy-middleware`)

const app = express()

const defaultConfig = {
  ws: true,
  secure: false,
  changeOrigin: true,
  on: {
    proxyReq: (proxyReq, req, res) => {
      fixRequestBody(proxyReq, req)
    },
    // Without this function, another error will occur
    // Without this function, another error will occur
    // Without this function, another error will occur
    error: (err, req, res) => {
      console.log(err)
    },
  },
  logLevel: `silent`,
  // proxyTimeout: 60 * 1000,
  // timeout: 60 * 1000,
}

app.use(`/amap/`, createProxyMiddleware({ ...defaultConfig, target: `https://restapi.amap.com/`}))
app.listen(8840)

Note: The above information may only apply to my use case.