I built an oauth2 url with query params using URLSearchParmas
API. However, the output URL didn't return an expected url. Can anyone help me understand the difference between those two APIs and how can I get the same result as the output of encodeURIComponent
, using URLSearchParams
? Thanks!
const expected = encodeURIComponent('code id_token'); // code%20id_token
const search = new URLSearchParams();
search.set('response_type', 'code id_token');
search.toString(); // code+id_token
encodeURI and encodeURIComponent are used for different purposes. encodeURI is used to encode a full URL whereas encodeURIComponent is used for encoding a URI component such as a query string. There are 11 characters which are not encoded by encodeURI, but encoded by encodeURIComponent. List: ? ? encodeURIComponent does not encode -_.!~*' ().
decodeURI (): It takes encodeURI (url) string as parameter and returns the decoded string. decodeURIComponent (): It takes encodeURIComponent (url) string as parameter and returns the decoded string.
URLs can only have certain characters from the standard 128 character ASCII set. Reserved characters that do not belong to this set must be encoded. This means that we need to encode these characters when passing into a URL.
Use of the encodeURI () method is a bit more specialized than escape () in that it encodes for URIs as opposed to the querystring, which is part of a URL. Use this method when you need to encode a string to be used for any resource that uses URIs and needs certain characters to remain un-encoded.
According to WHATWG, URLSearchParams
uses application/x-www-form-urlencoded
format. While it's suitable for decoding URL queries, for encoding it can lead to unexpected results such as spaces being encoded as +
and extra characters such as ~
being percent-encoded. It's better to use encodeURIComponent
instead:
Having an object:
const params = {
text1: 'aaa bbb',
text2: '-._*~()'
}
Instead of:
url.search = (new URLSearchParams(params)).toString()
Use:
url.search = Object.entries(params)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&')
Also, according to MDN even encodeURIComponent
doesn't conform to newer RFC 3986 which defines more characters to escape, for example *
. While it's probably safe not to escape these additional characters if you aren't using them as field separators, if you want to be strictly conformant to latest RFC, use this updated implementation from MDN:
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16).toUpperCase();
});
}
A playground for experimenting:
const params = {
text1: 'aaa bbb',
text2: '-._*~()'
}
const url1 = new URL('http://example.com')
const search1 = new URLSearchParams(params)
url1.search = search1 // Incorrect
console.log('URLSearchParams', url1.toString())
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
})
}
const url2 = new URL('http://example.com')
const search2 = Object
.entries(params)
.map(([key, value]) => `${fixedEncodeURIComponent(key)}=${fixedEncodeURIComponent(value)}`)
.join('&')
url2.search = search2 // Correct
console.log('fixedEncodeURIComponent', url2.toString())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With