chimurai / http-proxy-middleware

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

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client #412

Open cdisk opened 4 years ago

cdisk commented 4 years ago

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.

I want to use both pathRewrite and followRedirects. I use the vue webpack config this funtions. But When I add followRedirects config attribute,the console show me this error.

Steps to reproduce

  1. create vue project.
  2. add vue.config.js
  3. add proxy config to vue.config.js file.
  4. add pathRewrite and followRedirects to proxy node.
  5. run command yarn serve to start project.
  6. use ajax call target url in browser.
  7. the yarn console display following errors and stop the project:

Here is my vue.config.js file:

    devServer: {
        proxy: {
            '/api': {
                target: 'http://127.0.0.1:8581/', // 反代目标地址
                changeOrigin: true,
                // autoRewrite: true,
                // xfwd: true,
                // prependPath: true,
                followRedirects: true,
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }

Here is the error message displayed in the console:

_http_outgoing.js:485
    throw new ERR_HTTP_HEADERS_SENT('set');
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ClientRequest.setHeader (_http_outgoing.js:485:11)
    at RedirectableRequest.setHeader (/root/workspaces/sqwl/hzsc-pc/node_modules/http-proxy/node_modules/follow-redirects/index.js:118:24)
    at ProxyServer.onProxyReq (/root/workspaces/sqwl/hzsc-pc/node_modules/@vue/cli-service/lib/util/prepareProxy.js:97:20)
    at ProxyServer.emit (/root/workspaces/sqwl/hzsc-pc/node_modules/eventemitter3/index.js:184:35)
    at RedirectableRequest.<anonymous> (/root/workspaces/sqwl/hzsc-pc/node_modules/http-proxy/lib/http-proxy/passes/web-incoming.js:132:27)
    at RedirectableRequest.emit (events.js:223:5)
    at ClientRequest.eventHandlers.<computed> (/root/workspaces/sqwl/hzsc-pc/node_modules/http-proxy/node_modules/follow-redirects/index.js:17:24)
    at ClientRequest.emit (events.js:228:7)
    at tickOnSocket (_http_client.js:684:7)
    at onSocketNT (_http_client.js:723:5)
    at processTicksAndRejections (internal/process/task_queues.js:81:21) {
  code: 'ERR_HTTP_HEADERS_SENT'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

please help me.

uranium93 commented 4 years ago

any updates about this Issue ? :/

maks-humeniuk commented 3 years ago

Not sure if it's relevant, but I also had this error in Angular application, while trying to proxy POST request via pathRewrite.

It appears that pathRewrite works fine for GET requests.

pathRewrite: () => '/mocks/get-heroes-response.mock.json'

Yes, it could also be a function, not an object.

But for POST and PUT bypass should be used instead.

bypass: (request) => {
    if (request.method === 'POST') {
        request.method = 'GET';
        return '/mocks/create-hero-response.mock.json';
    }
}

Using pathRewrite for POST and PUT also works, but with error you sent.

maks-humeniuk commented 3 years ago

After new research I figured out that bypass suffers from https://github.com/webpack/webpack-dev-server/issues/829.

Luckily, you could substitute it with pathRewrite like this.

// for non-GET requests
pathRewrite: (path, request) => {
    request.method === 'GET';
    return '/path/to/mock.json';
}

// for GET requests
pathRewrite: () => '/path/to/mock.json'

If you have multiple returns though, you should wrap request.method === 'GET'; with e.g. if (request.method === 'POST') {} to avoid infinite loop situations.

// for non-GET requests
pathRewrite: (path, request) => {
    if (request.method === 'POST') {
        request.method === 'GET';
        return '/path/to/post-mock.json';
    }
    if (request.method === 'PUT') {
        request.method === 'GET';
        return '/path/to/put-mock.json';
    }
}

Or, more elegant solution.

// for non-GET requests
pathRewrite: (path, request) => {
    const post = request.method === 'POST';
    const put = request.method === 'PUT';
    if (post || put) {
        request.method === 'GET';
    }
    if (post) {
        return '/path/to/post-mock.json';
    }
    if (put) {
        return '/path/to/put-mock.json';
    }
}
uranium93 commented 3 years ago

Little update regarding this. we faced an issue with same error message using express with http-proxy-middleware and the issue was that in implementation next() was called twice, once in the middleware and the other one onError without return.