Solvedhttp proxy middleware [ Question ] How do you manipulate proxy response

Hi, I'm using Express 4,

In normal way, I can do the following

    app.get('/v1/users/:username', function(request, response, next) {
        var username = request.params.username;
        findUserByUsername(username, function(error, user) {
            if (error) return next(error);
            return response.render('user', user);
        });
    });

But how do I execute custom logic if I'm using proxy, let's say I want to manipulate some of the data before response to the user? Is there a good pattern to do that with this middleware ?

app.use('/api', proxy({target: 'http://www.example.org', changeOrigin: true}));

39 Answers

✔️Accepted Answer

here is my answer,

onProxyRes :function(proxyRes, req, res){
      var _write = res.write;
      var output;
      var body = "";
      proxyRes.on('data', function(data) {
          data = data.toString('utf-8');
          body += data;
      });
      res.write = function (data) {
        try{
          eval("output="+body)
          output = mock.mock(output)
          _write.call(res,JSON.stringify(output));
        } catch (err) {}
      }
    }

add onProxyRes option on the http-proxy-middleware
use the data event on the proxyRes to get the output
then modify the output in res.write

Other Answers:

My solution:

const zlib = require('zlib');
...
onProxyRes: (proxyRes, req, res) => {
	let originalBody = new Buffer('');
	proxyRes.on('data', function (data) {
		originalBody = Buffer.concat([originalBody, data]);
	});
	proxyRes.on('end', function () {
		const bodyString = zlib.gunzipSync(originalBody).toString('utf8')
		const objectToModify = JSON.parse(bodyString)
		objectToModify.modification = 'Mickey Mouse'
		res.end(JSON.stringify(objectToModify));
	});
},
selfHandleResponse: true . // necessary to avoid res.end being called automatically
...

This was my final solution (inspired by @kokarn 's solution over at http-party/node-http-proxy#796

I'm using this in a webpack dev server setup by create-react-app, hence the comment further down.

onProxyRes: ( proxyRes, req, res ) => {
    const _writeHead = res.writeHead;
    let _writeHeadArgs;
    const _end = res.end;
    let body = '';

    proxyRes.on( 'data', ( data ) => {
      data = data.toString( 'utf-8' );
      body += data;
    } );

    // Defer writeHead
    res.writeHead = ( ...writeHeadArgs ) => {
      _writeHeadArgs = writeHeadArgs;
    };

    // Defer all writes
    res.write = () => {};

    res.end = ( ...endArgs ) => {
      // Do everything in the end. Means we wont be streaming the response but who cares in a dev env..
      const output = body
        .replace( /stufftoreplace/g, '/leweb' );

      if ( proxyRes.headers && proxyRes.headers[ 'content-length' ] ) {
        res.setHeader( 'content-length', output.length );
      }

      // This disables chunked encoding
      res.setHeader( 'transfer-encoding', '' );

      // Disable cache for all http as well
      res.setHeader( 'cache-control', 'no-cache' );

      _writeHead.apply( res, _writeHeadArgs );

      if ( body.length ) {
         // Write everything via end()
        _end.apply( res, [ output ] );
      } else {
        _end.apply( res, endArgs );
      }
    };
  }

Perhaps the core problem is that response proxy gets from original source is not passed through existing express middleware chain?
Express already has an ecosystem of middleware, but for some reason we have to duplicate it's functionality in onProxyRes. This doesn't seem right.

@mrt123 's response got us 90% there. But if you need to gzip your response before sending it back out, here's how to do that:

 onProxyRes: (proxyRes, req, res) => {
  let originalBody = Buffer.from([]);
  proxyRes.on('data', data => {
    originalBody = Buffer.concat([originalBody, data]);
  });

  proxyRes.on('end', () => {
    const bodyString = zlib.gunzipSync(originalBody).toString('utf8');
    const newBody = doSomeReplacementStuff(bodyString);

    res.set({
      'content-type': 'text/html; charset=utf-8',
      'content-encoding': 'gzip'
    });
    res.write(zlib.gzipSync(newBody));
    res.end();
  });
},
selfHandleResponse: true,

Related Issues:

57
http proxy middleware [ Question ] How do you manipulate proxy response
here is my answer Hi I'm using Express 4 In normal way I can do the following But how do I execute c...
4
http proxy middleware proxy to https errors in Node 0.12
Don't think it is an issue of the middleware Looking at the http-proxy proxy-http-to-https.js exampl...
3
http proxy middleware Cookie not saved in browser
Since you are trying to proxy between http <-> https; You might want to check your cookie flags ...
147
express What is the default timeout of a req in express?
@flickz @vitoravale I've found two ways to make it work Uploading a blob on azure storage and at tim...
77
apollo server Apollo Server 3.0 Roadmap
IMO it would be a great idea to implement the previous roadmap before creating the new 😜 I'm person...
67
apollo server TypeScript import issues with apollo-server-express
I fixed it by installing the types for graphql Hello Yesterday while I was trying out Apollo for the...
53
passport req.isAuthenticated() returning false immediately after login
@dougwilson ultimately provided the answer over here express-session tries to delay the redirect ...
43
apollo server Serverless Subscriptions
Why not AppSync? It has Apollo Server base I personally don't like AppSync for the following reasons...
39
fiber 📢 v2 - Changelog
Thanks @pofl Updated September 14 2020 ( 🚀 v2 benchmark results ) Dear Gophers after long discussio...
37
apollo server Apollo Server 2 - Override CORS Default
For anyone else reading this newer versions of apolloServer accept the cors property in the applyMid...
36
apollo server apollo-server-testing context is not receiving the req object
I just ran into this I don't consider it a true integration test unless you can actually test how yo...
36
graphql upload Node 13 support
For anyone still hitting this the resolutions seems to work correctly without globbing ...
35
apollo server Apollo 2 serverless giving 403
@jatinvmehta Ok I think I figured out the issue I followed this tutorial https://www.apollographql.c...
31
apollo server throwing AuthenticationError should set the response status to 401 Unauthorized
I did not manage to get the didEncounterError hook to do what i wanted so i used willSendResponse to...
23
apollo server apollo-server-plugin-response-cache: cache hint not working
It's disappointing the cache only works if you set a global caching settings: I am using merge-graph...
23
express net::ERR_CONTENT_LENGTH_MISMATCH
I ran into this issue using both Express and Nginx This SO post helps me I fixed the problem by sett...
21
postgraphile Adding subscriptions
Super excited to announce that we just released 4.4.0-alpha.0 which includes OSS subscriptions and l...
20
apollo server Server 2.0: Data Sources
@martijnwalraven @jkdowdle Updated Babel to v 7.0 (still was using 6) added node version to the conf...
20
apollo server Hot schema reload with Apollo server v2
I don't understand why this is closed Not everyone is interested in using Apollo Gateway but some st...
19
apollo server How to split schemas into separate files?
@helfer Thanks but unfortunately it's not solve my problem My app is modularity and in every module ...
19
express validator Schema with isIn validation
Try options: [['one' 'two' 'zero']] The options array is for passing each param Since isIn() expects...
19
serverless express [Question] Internal server error when request method OPTIONS
With the help from staff on AWS forums I've resolved it by adding: which now returns a correct 200 r...
18
apollo server Migrating from 1.0 to 2.0: How to add middleware?
@avirdz One workaround is to use the context function and the provided req parameter to manually inj...
18
postgraphile document how to do a mutation
I set up the superb forum_example tutorial and thanks to Graphiql autocomplete (which mostly worked)...
17
express Express equivalent of res.end(data, 'binary')?
try res.send(new Buffer(pdfData 'binary')) or the res.type() / res.end(pdfData 'binary') combo shoul...
16
postgraphile Where JWT token is read from and how to use it with GraphiQL?
However In the documentation it says: After a JSON Web Token has been verified and decoded ...
15
apollo server Can't set GraphQL Playground options like preset auth headers for tabs dynamically
@rgoldfinger In order for what you have to work you have to import defaultPlaygroundOptions from apo...
14
serverless express Async handler doesn't work on node 8.10
PR for this here #173 Note that I plan on improving the interface in a future breaking change (aws-s...
13
apollo server Add graphql-middleware support
Hey @Alvyre 👋 Since we still haven't implemented this you could use the alternative approach we men...
12
apollo server Apollo Server supports only GET/POST requests.
@texascj This was helpful you can also change the HttpApi payload format version back to 1.0 SAM tem...
12
apollo server Expose request Object to formatError
I'd very much like to get the request context in formatError I would like to log the request body wh...
12
serverless express Can't get the API Gateway event object
In case any other lost souls who are encountering Missing x-apigateway-event or x-apigateway-context...
11
apollo server Request: Provide context on global error handlers
I am having the same need In my case I want to log the error an report it to bugsnag However ...
11
apollo server Throwing circular object in resolver breaks apollo-server (500 HTTP error)
Workaround: use the formatResponse option function to catch the circular reference re-serialize with...
10
express Middleware that needs to modify res.body
as seen in the documentation http://expressjs.com/api.html#res.send it appears what you need is ...
6
apollo server Access to query variables in validationRules
Here is a working example of graphql-query-complexity integration with Apollo Server 💪 https://gith...
5
apollo server Error types (instanceof) are lost if thrown from resolver
Same for me it just returns GraphQLError for everything My version is 2.6.4 But I believe this bug a...
4
postgraphile Feature Request: Batch query support
To answer myself---I found the following solution works: PostgresQL setup: GraphQL query: ...
3
Angular Full Stack How to secure the api?
On the client side: You need to use the AuthHttp with class from angular2-jwt instead of the basic H...
3
express validator checkSchema - custom validator and exists errorMessage
Hm the exists one is strange by doesn't work do you mean the error message is still Invalid value? I...
3
express app.locals fails
Do this? I'm using Express 4.0.0-rc4 and trying to do the following: Each time that I do that I get ...
3
express Replace route at runtime
Does this help? I was not really able to understand what you were doing in the linked gist ...
3
fiber Problem with Route path
Thanks for your reporting! But I don't it is counted as a bug According to your example ...
3
postgraphile "disableDefaultMutations" disable all mutations?
The issue does not lie in SQL - I was talking about allowing custom mutations to utilise the FooPatc...
3
graphql upload Error: A ReadStream cannot be created from a destroyed WriteStream.
I suspect this is behaving correctly and that your uploadImage function is likely being called after...
63
v2ray core vmess协议设计和实现缺陷可导致服务器遭到主动探测特征识别(附PoC)
简而言之,如果 GFW 怀疑你鸡上有个 vmess + tcp,他抓个包,然后按上面的方法进行重放,在我电脑上实测不用一秒钟你的 vmess + tcp 就被识别了,更别提 GFW 了。希望大家予以重...
3831
axios Axios catch error returns javascript error not server response
I have exactly the same environment Try this: Modify from console.log(error) to console.log(error.re...
2346
jest Bug: Watch mode on Linux causes a ENOSPC Node.js error
From my findings its not related to Jest at all On Linux (or Mac) we have a max number of system wat...
1975
react RFClarification: why is setState asynchronous?
So here’s a few thoughts This is not a complete response by any means but maybe this is still more h...