encodeURIComponent 与 URLSearchParams 的不同输出

sup*_*tle 6 url query-parameters oauth-2.0

我使用URLSearchParmasAPI构建了一个带有查询参数的 oauth2 url 。但是,输出 URL 没有返回预期的 URL。任何人都可以帮助我理解这两个API之间的差异,我怎么能得到相同的结果的输出encodeURIComponent,使用URLSearchParams?谢谢!

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
Run Code Online (Sandbox Code Playgroud)

Zme*_*mey 7

根据WHATWGURLSearchParams使用application/x-www-form-urlencoded格式。虽然它适用于解码 URL 查询,但对于编码它可能会导致意外结果,例如空格被编码为+和额外字符(例如~百分比编码)。最好encodeURIComponent改用:

有对象:

const params = {
  text1: 'aaa bbb',
  text2: '-._*~()'
}
Run Code Online (Sandbox Code Playgroud)

代替:

url.search = (new URLSearchParams(params)).toString()
Run Code Online (Sandbox Code Playgroud)

用:

url.search = Object.entries(params)
  .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
  .join('&')
Run Code Online (Sandbox Code Playgroud)

此外,根据MDN甚至encodeURIComponent不符合较新的RFC 3986,它定义了更多要转义的字符,例如*. 如果您不将这些附加字符用作字段分隔符,则不转义这些字符可能是安全的,但如果您想严格遵守最新的 RFC,请使用MDN 中的此更新实现:

function fixedEncodeURIComponent(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}
Run Code Online (Sandbox Code Playgroud)

一个试验场:

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)
    })
}
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())
Run Code Online (Sandbox Code Playgroud)