How to get the full URL for a request in Hapi

2019-04-18 13:05发布

问题:

In my hapijs app, given a Request object, how can I find the original, unparsed, unmodified URL?

function getRequestUrl (request) {
    return ...; // What goes here?
}

I've found that I can piece it together somewhat from Request.info.host, Request.path, and Request.query, but it lacks the scheme (ie, http vs https), and is a bit of a kludge. Isn't the plain URL available somewhere?

回答1:

The full URL isn't stored somewhere you can get it. You need to build it yourself from the parts:

const url = request.connection.info.protocol + '://' + request.info.host + request.url.path;

Even though it might seem kludgey, it makes sense if you think about it because there is no original, unparsed, unmodified URL. The HTTP request that goes over the wire doesn't contain the URL as typed into the browser address bar for instance:

GET /hello?a=1&b=2 HTTP/1.1      // request.url.path
Host: localhost:4000             // request.info.host
Connection: keep-alive
Accept-Encoding: gzip, deflate, sdch
...

And you only know the protocol based on whether the hapi server connection is in TLS mode or not (request.connection.info.protocol).

Things to be aware of

If you check either:

request.connection.info.uri or request.server.info.uri

the reported hostname will be the hostname of the actual machine that the server is running on (the output of hostname on *nix). If you want the actual host the person typed in the browser (which might be different) you need to check request.info.host which is parsed from the HTTP request's Host header)

Proxies and X-Forwarded-Proto header

If your request got passed through a proxy(ies)/load balancers/HTTPS terminators, it's possible somewhere along the line HTTPS traffic got terminated and was sent to your server on an HTTP connection, in this case you'll want use the value of the x-forwarded-proto header if it's there:

const url = (request.headers['x-forwarded-proto'] || request.connection.info.protocol) + '://' + request.info.host + request.url.path;

With template strings:

const url = `${request.headers['x-forwarded-proto'] || request.connection.info.protocol}://${request.info.host}${request.url.path}`;


回答2:

hapi-url solves this exact problem. It is prepared to work with X-Forwarded headers to run behind a proxy. There is also an option to override the automatic resolution if the library is not able to resolve the URL correctly.



回答3:

I use the following syntax now (using coffee script):

server.on 'response', (data) ->
  raw = data.raw.req
  url = "#{data.connection.info.protocol}://#{raw.headers.host}#{raw.url}"
  console.log "Access to #{url}"

Or as javascript:

​server.on('response', function(data) {
  var raw = data.raw.req;
  var url = data.connection.info.protocol + "://" + 
  raw.headers.host + raw.url;
  console.log("Access to " + url);
});

That gives you the exact URL like the user requested it.



回答4:

You can't get the URL. You have to generate it. I'm using this one:

const url = request.headers['x-forwarded-proto'] + '://' +
            request.headers.host + 
            request.url.path;


标签: url hapijs