36

I'm messing around with node and I'm trying to get an instance of the URL class (because of those handy properties). Like:

const { URL } = require('url');
(...)
http.createServer((request,response) => {
    let uri = new URL(request.url);
    (...)
}

But it fails with

TypeError [ERR_INVALID_URL]: Invalid URL: /

It's funny because

const url = require('url');
url.parse();

works. So I got curious about it. I understand this later method is older.

I'm developing locally so to send a request I use localhost:8000 in the browser.

How do I use the information in request to instantiate a new URL object?

Info and things I've looked on already:

node -v
v9.3.0

https://nodejs.org/api/url.html#url_class_url
https://stackoverflow.com/questions/44738065/uncaught-typeerror-url-is-not-a-constructor-using-whatwg-url-object-support-for
https://stackoverflow.com/questions/45047840/in-node-js-how-to-get-construct-url-string-from-whatwg-url-including-user-and-pa
https://stackoverflow.com/questions/47481784/does-url-parse-protect-against-in-a-url
https://stackoverflow.com/questions/17184791/node-js-url-parse-and-pathname-property
1
  • 2
    The error is telling you the problem. '/' is an invalid URL format. '/' is a path. For it to be a valid URL it needs a host, protocol, and path. Commented Jan 10, 2018 at 22:05

1 Answer 1

41

As Joshua Wise pointed out on Github (https://github.com/nodejs/node/issues/12682), the problem is that request.url is NOT an absolute URL. It can be used as a path or relative URL, but it is missing the host and protocol.

Following the API documentation, you can construct a valid URL by supplying a base URL as the second argument. This is still awkward because the protocol is not easily available from request.headers. I simply assumed HTTP:

var baseURL = 'http://' + request.headers.host + '/';
var myURL = new URL(request.url, baseURL);

This is obviously not an ideal solution, but at least you can take advantage of the query string parsing. For example,

URL {
  href: 'http://localhost:8080/?key1=value1&key2=value2',
  origin: 'http://localhost:8080',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'localhost:8080',
  hostname: 'localhost',
  port: '8080',
  pathname: '/',
  search: '?key1=value1&key2=value2',
  searchParams: URLSearchParams { 'key1' => 'value1', 'key2' => 'value2' },
  hash: '' }
Sign up to request clarification or add additional context in comments.

2 Comments

I like your solution. We could abstract the baseURL string building to a function that figures out the protocol, perhaps?
How about making the base URL exemplary to express that it is mandatory yet still exemplary? Example: 'example://example.test'. Notes: Leave the ending slash out to keep parsing the pathname from the relative URL. The relative nature of the pathname then can be verified afterwards more easily (first (few) character(s)). .origin will be null unless the protocol of the relative URL gives an acceptable origin. Benefit is there is no hidden dependency of the Request while it still applies to IANA / RFC conformance, not misleading on the URI scheme (misnamed protocol in Node URL).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.