简体   繁体   中英

Hapi.js Proxy - change the response before reply

I'm trying to test Hapi.js for a new project I'm working on My goal is to trigger a request on my Hapi server and this request will trigger another request on a remote server using Hapi proxy, and the response will be only specific properties from the remote response

To test this a request to /api/type3/name must be made which will invoke an API call to GitHub's API to get the user object

Code:

server.route({
    method: 'GET',
    path: '/api/type3/{name}',
    handler: {
      proxy: {
        mapUri: function(request,callback){
            callback(null,'https://api.github.com/users/'+request.params.name);
        },
        onResponse: function(err, res, request, reply, settings, ttl){
           console.log(res); 
           reply(res);
        },
        passThrough: true,
        xforward: true
      }
    }
});

The response from the above code is the response object from GitHub Now I need to save this response so I can manipulate it and return only what I need

But when I debug the response object it contains a lot of data and I can't find the response payload inside of it

So how to extract only the response from GitHub from the response object ?

Thanks a lot

The res object is anhttp.IncomingMessage . If you want to work with the body of the response you need to read all the data off it first.

You have 2 choices for doing this.

1) Vanilla Node

onResponse: function(err, res, request, reply, settings, ttl){

    var body = '';

    res.on('data', function (chunk) {
        body += chunk;
    });

    res.on('end', function () {
        console.log(body);  
        reply(body);
    });
}

2) Using Wreck (a module for working with HTTP in Node made by the Hapi folks)

var Wreck = require('wreck');

onResponse: function(err, res, request, reply, settings, ttl){
   Wreck.read(res, null, function (err, payload) {
       console.log(payload);
       reply(payload);
   });
}

In the wreck case above, you could do

payload = payload.toString();

To convert the buffer to actual data.

I want to load xml data from remote server and convert the response to json. This thread helped me lot to find a solution that worked for me. But in my case the code above doesn't worked too, because the response from the remote server was gzipped. In my console there were only unreadable data.

I tried to enable automatic payload parsing for the proxy but it was not successful. Finally i had to unzip the response by myself with 'zlib'.

This code is working for me:

'use strict'

const url = require('url')
const h2o2 = require('h2o2')
const Hapi = require('hapi')
const parseString = require('xml2js').parseString
var zlib = require('zlib')
const _ = require('lodash')

var remoteServerUrl = 'http://some-url.com:2434'
var originUrl = 'http://localhost:3000'

// Create a server with a host and port
const server = new Hapi.Server()
server.connection({
  host: 'localhost',
  port: 3001,
  routes: {
    cors: {
      origin: [originUrl],
    },
  },
})

server.register({
  register: h2o2,
}, function (err) {
  server.start(function (err) {
    console.log('Proxy Server started at: ' + server.info.uri)
  })
})

server.route({
  method: '*',
  path: '/proxy/{path*}',

  config: {
    payload: {
      // parse: true,   // didn't worked for me
      // parse: 'gzip', // didn't worked for me
      output: 'stream',
    },
  },

  handler: {

    proxy: {
      passThrough: true,
      timeout: 15000,
      acceptEncoding: false,

      mapUri (request, callback) {
        callback(null, url.format({
          protocol: url.parse(remoteServerUrl).protocol,
          host: url.parse(remoteServerUrl).host,
          port: url.parse(remoteServerUrl).port,
          pathname: request.params.path,
          query: request.query,
        }))
      },

      onResponse (err, res, request, reply, settings, ttl) {
        if (err) {
          console.error('Hapi server error: ', err)
        }

        // let's unzip the response 
        var gunzip = zlib.createGunzip()
        var xmlStr = ''

        gunzip.on('data', function (data) {
          xmlStr += data.toString()
        })

        gunzip.on('end', function () {
          // do something with the string
          // in this case convert xml to json string
          parseString(xmlStr, {}, function (err, result) {
            // send result back
            reply(result)
          })
        })

        res.pipe(gunzip)
      },
    },
  },
})

Maybe this helps someone else ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM