2937

How do you safely encode a URL using JavaScript such that it can be put into a GET string?

var myUrl = "http://example.com/index.html?param=1&anotherParam=2";var myOtherUrl = "http://example.com/index.html?url=" + myUrl;

I assume that you need to encode themyUrl variable on that second line?

Peter Mortensen's user avatar
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
askedDec 2, 2008 at 2:37
nickf's user avatar
5

22 Answers22

3236

Check out the built-in functionencodeURIComponent(str) andencodeURI(str).
In your case, this should work:

var myOtherUrl =        "http://example.com/index.html?url=" + encodeURIComponent(myUrl);
user229044's user avatar
user229044
241k41 gold badges347 silver badges350 bronze badges
answeredDec 2, 2008 at 2:43
Buu's user avatar
Sign up to request clarification or add additional context in comments.

13 Comments

How about adding the explanation @cms gave?escape is also a valid option.
according to @CMSencodeURI is not really safe for URL encoding.
@AnaelFavre because it is meant to encode the whole URL, which doesn't allow characters such as:,/,@ etc. These 2 methods are not to be used interchangeable, you must know what you are encoding to use the right method.
NOTE: encodeURIComponent is only intended to be used on a URL's path. Query parameters follow an older percent-encoding specification which expects spaces to be encoded as "+" instead of "%20". Seethis S.O. question to learn more. Some servers may be lenient with this incorrect encoding, but your mileage may vary. In modern JavaScript, I would recommend encoding via URL or URLSearchParams asthis answer recommends.
|
1709

You have three options:

  • escape() will not encode:@*/+

  • encodeURI() will not encode:~!@#$&*()=:/,;?+'

  • encodeURIComponent() will not encode:~!*()'

But in your case, if you want to pass aURL into aGET parameter of other page, you should useescape orencodeURIComponent, but notencodeURI.

See Stack Overflow questionBest practice: escape, or encodeURI / encodeURIComponent for further discussion.

user229044's user avatar
user229044
241k41 gold badges347 silver badges350 bronze badges
answeredDec 2, 2008 at 2:49
Christian C. Salvadó's user avatar

10 Comments

The character encoding used with escape is variable. Stick with encodeURI and encodeURIComponent, which use UTF-8.
Be careful. That escape converts non-ASCII characters into its Unicode escape sequences, like%uxxx.
I am using encodeURIComponent and noticing it will not encode pipe characters |
@kevzettler - why should it do that? The pipes aren't of semantic importance in a URI.
@GiovanniP: People who allow German, French, Japanese, Chinese, Arabic characters as input and pass theses parameters via GET or POST.
|
209

Stick withencodeURIComponent(). The functionencodeURI() does not bother to encode many characters that have semantic importance in URLs (e.g. "#", "?", and "&").escape() is deprecated, and does not bother to encode "+" characters, which will be interpreted as encoded spaces on the server (and, as pointed out by others here, does not properly URL-encode non-ASCII characters).

There is a niceexplanation of the difference betweenencodeURI() andencodeURIComponent() elsewhere. If you want to encode something so that it can safely be included as a component of a URI (e.g. as a query string parameter), you want to useencodeURIComponent().

answeredMay 29, 2011 at 23:54
Mike Brennan's user avatar

Comments

106

The best answer is to useencodeURIComponent onvalues in the query string (and nowhere else).

However, I find that many older APIs want to replace " " with "+" so I've had to use the following:

const value = encodeURIComponent(value).replaceAll('%20','+');const url = 'http://example.com?lang=en&key=' + value

escape is implemented differently in different browsers andencodeURI doesn't encode many characters (like # and even /) -- it's made to be used on a full URI/URL without breaking it – which isn't super helpful or secure.

And as @Jochem points out below, you may want to useencodeURIComponent() on a (each) folder name, but for whatever reason these APIs don't seem to want+ in folder names so plain oldencodeURIComponent works great.

Example:

const escapedValue = encodeURIComponent(value).replaceAll('%20','+');const escapedFolder = encodeURIComponent('My Folder'); // no replaceconst url = `http://example.com/${escapedFolder}/?myKey=${escapedValue}`;
answeredDec 15, 2012 at 8:47
Ryan Taylor's user avatar

8 Comments

Please note, you should only replace %20 with + symbols after the first question mark (which is the 'query' part of the URL). Let's say I want to browse tohttp://somedomain/this dir has spaces/info.php?a=this has also spaces. It should be converted to:http://somedomain/this%20dir%20has%spaces/info.php?a=this%20has%20also%20spaces but many implementations allow '%20' in the querystring to be replaced by '+'. Nevertheless, you cannot replace '%20' with '+' in the path-section of the URL, this will result in a Not Found error unless you have a directory with a+ instead of a space.
@Jochem Kuijpers, definitely, you wouldn't put "+" in a directory. I'd only apply this to the query parameter values themselves (or keys if needed), not the entire URL, or even the entire query string.
I would replace in value rather than in the result of the encoding
@njzk2 unfortunatelyencodeURIComponent('+') would give you%2B, so you'd have to use two regular expressions... which I suppose is kinda why this works, because '+' are ' ' are encoded differently in the end.
Nice one, though we need to use .replaceAll('%20','+') to replace all spaces, not only first one
|
46

Modern solution (2021)

Since the other answers were written, theURLSearchParams API has been introduced. It can be used like this:

const queryParams = { param1: 'value1', param2: 'value2' }const queryString = new URLSearchParams(queryParams).toString()// 'param1=value1&param2=value2'

It also encodes non-URL characters.

For your specific example, you would use it like this:

const myUrl = "http://example.com/index.html?param=1&anotherParam=2";const myOtherUrl = new URL("http://example.com/index.html");myOtherUrl.search = new URLSearchParams({url: myUrl});console.log(myOtherUrl.toString());

This solution is also mentionedhere andhere.

answeredNov 15, 2019 at 14:30
Qback's user avatar

1 Comment

The subtle part that was causing me problems (encoding spaces as%20 instead of+) was solved by using.toString() on the URLSearchParams
44

I would suggest to use theqs npm package:

qs.stringify({a:"1=2", b:"Test 1"}); // gets a=1%3D2&b=Test+1

It is easier to use with a JavaScript object and it gives you the proper URL encoding for all parameters.

If you are using jQuery, I would go for the$.param method. It URL encodes an object, mapping fields to values, which is easier to read than calling an escape method on each value.

$.param({a:"1=2", b:"Test 1"}) // Gets a=1%3D2&b=Test+1
Peter Mortensen's user avatar
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answeredMay 13, 2013 at 3:32
Maksym Kozlenko's user avatar

3 Comments

I think that example provided is sufficient. If you need more information about $.param onapi.jquery.com/jquery.param
Almost everyone uses jQuery and I feel more comfortable indeed with this instead of encoreURIComponent
qs great, compact and usefull package. Vote up for the qs on backend
17

I think now in 2022 to be really safe, you should always consider constructing your URLs using theURL() interface. It'll do most of the job for you. So coming to your code,

const baseURL = 'http://example.com/index.html';const myUrl = new URL(baseURL);myUrl.searchParams.append('param', '1');myUrl.searchParams.append('anotherParam', '2');const myOtherUrl = new URL(baseURL);myOtherUrl.searchParams.append('url', myUrl.href);console.log(myUrl.href);// Outputs: http://example.com/index.html?param=1&anotherParam=2console.log(myOtherUrl.href);// Outputs: http://example.com/index.html?url=http%3A%2F%2Fexample.com%2Findex.html%3Fparam%3D1%26anotherParam%3D2console.log(myOtherUrl.searchParams.get('url'));// Outputs: http://example.com/index.html?param=1&anotherParam=2

Or...

const params = new URLSearchParams(myOtherUrl.search);console.log(params.get('url'));// Outputs: http://example.com/index.html?param=1&anotherParam=2

Something like this is assured not to fail.

answeredJul 1, 2021 at 13:11
m4heshd's user avatar

Comments

15

encodeURIComponent() is the way to go.

var myOtherUrl = "http://example.com/index.html?url=" + encodeURIComponent(myUrl);

But you should keep in mind that there are small differences from PHP versionurlencode() and as @CMS mentioned, it will not encode every character. Guys athttp://phpjs.org/functions/urlencode/ made JavaScript equivalent tophpencode():

function urlencode(str) {  str = (str + '').toString();  // Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current  // PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following.  return encodeURIComponent(str)    .replace('!', '%21')    .replace('\'', '%27')    .replace('(', '%28')    .replace(')', '%29')    .replace('*', '%2A')    .replace('%20', '+');}
Peter Mortensen's user avatar
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answeredOct 1, 2015 at 8:03
Adam Fischer's user avatar

Comments

12

To encode a URL, as has been said before, you have two functions:

encodeURI()

and

encodeURIComponent()

The reason both exist is that the first preserves the URL with the risk of leaving too many things unescaped, while the second encodes everything needed.

With the first, you could copy the newly escaped URL into address bar (for example) and it would work. However your unescaped '&'s would interfere with field delimiters, the '='s would interfere with field names and values, and the '+'s would look like spaces. But for simple data when you want to preserve the URL nature of what you are escaping, this works.

The second is everything you need to do to make sure nothing in your string interfers with a URL. It leaves various unimportant characters unescaped so that the URL remains as human readable as possible without interference. A URL encoded this way will no longer work as a URL without unescaping it.

So if you can take the time, you always want to use encodeURIComponent() -- before adding on name/value pairs encode both the name and the value using this function before adding it to the query string.

I'm having a tough time coming up with reasons to use the encodeURI() -- I'll leave that to the smarter people.

answeredJan 26, 2017 at 21:31
Gerard ONeill's user avatar

Comments

10

What is URL encoding:

A URL should be encoded when there are special characters located inside the URL. For example:

console.log(encodeURIComponent('?notEncoded=&+'));

We can observe in this example that all characters except the stringnotEncoded are encoded with % signs. URL encoding is also known aspercentage encoding because it escapes all special characters with a %. Then after this % sign every special character has a unique code

Why do we need URL encoding:

Certain characters have a special value in a URL string. For example, the ? character denotes the beginning of a query string. In order to successfully locate a resource on the web, it is necessary to distinguish between when a character is meant as a part of string or part of the URL structure.

How can we achieve URL encoding in #"js" data-hide="false" data-console="true" data-babel="false">
// for a whole URI don't use encodeURIComponent it will transform// the / characters and the URL won't fucntion properlyconsole.log(encodeURIComponent("http://www.random.com/specials&char.html"));// instead use encodeURI for whole URL'sconsole.log(encodeURI("http://www.random.com/specials&char.html"));

We can observe f we put the whole URL inencodeURIComponent that the forward slashes (/) are also converted to special characters. This will cause the URL to not function properly anymore.

Therefore (as the name implies) use:

  1. encodeURIComponent on a certain part of a URL which you want to encode.
  2. encodeURI on a whole URL which you want to encode.
Peter Mortensen's user avatar
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answeredSep 23, 2018 at 8:35
Willem van der Veen's user avatar

Comments

7

To prevent double encoding, it's a good idea to decode the URL before encoding (if you are dealing with user entered URLs for example, which might be already encoded).

Let’s say we haveabc%20xyz 123 as input (one space is already encoded):

encodeURI("abc%20xyz 123")            //   Wrong: "abc%2520xyz%20123"encodeURI(decodeURI("abc%20xyz 123")) // Correct: "abc%20xyz%20123"
Peter Mortensen's user avatar
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answeredJan 5, 2017 at 18:49
serg's user avatar

Comments

6

You should not useencodeURIComponent() directly.

Take a look at RFC3986: Uniform Resource Identifier (URI): Generic Syntax

sub-delims = "!" / "$" / "&" / "'" / "(" / ")"/ "*" / "+" / "," / ";" / "="

The purpose of reserved characters is to provide a set of delimiting characters that are distinguishable from other data within a URI.

These reserved characters from the URI definition in RFC3986 ARE NOT escaped byencodeURIComponent().

MDN Web Docs: encodeURIComponent()

To be more stringent in adhering to RFC 3986 (which reserves !, ', (, ), and *), even though these characters have no formalized URI delimiting uses, the following can be safely used:

Use the MDN Web Docs function...

function fixedEncodeURIComponent(str) {  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {    return '%' + c.charCodeAt(0).toString(16);  });}
answeredMay 16, 2020 at 20:49
HoldOffHunger's user avatar

Comments

6

A similar kind of thing I tried with normal #"dateCreated" datetime="2013-05-14 06:48:44Z">

1 Comment

Can you explain your answer, please? E.g., why the magic hexadecimal number '2A'? (That is "*" (asterisk) in ASCII.) Please respond byediting (changing) your answer, not here in comments (********************without ******************** "Edit:", "Update:", or similar - the answer should appear as if it was written today).