如何对URL参数进行编码?

173

我正在尝试向一个这样的URL传递参数:

http://www.foobar.com/foo?imageurl=

我想传递一些参数,比如一个由另一个API自动生成的图像URL,该图像的链接结果为:

http://www.image.com/?username=unknown&password=unknown

然而,当我尝试使用这个URL时:

http://www.foobar.com/foo?imageurl=http://www.image.com/?username=unknown&password=unknown

它不起作用。

我还尝试在imageURL上使用encodeURI()encodeURIComponent(),但那也不起作用。


1
生成URL的是哪种语言?JavaScript吗? - Phil
7
请注意,即使使用https协议,您也不应该将密码放在URL中,因为每个客户端和服务器之间的路由器都会看到整个URL。请勿在URL中包含密码。 - fabb
这个回答解决了你的问题吗?如何在Javascript中创建查询参数? - Nick Grealy
1
@fabb 看起来并不是这样的:https://dev59.com/4XRB5IYBdhLWcg3w1Kde#499594 - Erhannis
@Erhannis GET路径和参数在HTTPS中进行了加密,但在HTTP中没有(好吧,没人应该使用HTTP,但仍然...)。然而,更严重的是,服务器日志和任何分析工具都将看到GET参数,因此您将在Apache日志和Google Analytics中记录明文密码。如果启用了referrer header,则它们也会通过referrer header发送。请参见https://security.stackexchange.com/questions/233795/are-url-parameters-of-get-and-post-requests-over-https-secure - Dan W
4个回答

218

使用PHP

echo urlencode("http://www.image.com/?username=unknown&password=unknown");

结果

http%3A%2F%2Fwww.image.com%2F%3Fusername%3Dunknown%26password%3Dunknown

使用JavaScript:

var myUrl = "http://www.image.com/?username=unknown&password=unknown";
var encodedURL= "http://www.foobar.com/foo?imageurl=" + encodeURIComponent(myUrl);

演示:http://jsfiddle.net/Lpv53/


6
这个问题不是关于PHP的,而是关于Javascript的。 - Flimm

64
使用新的ES6 Object.entries(),可以使嵌套的map/join更有趣。
const encodeGetParams = p => 
  Object.entries(p).map(kv => kv.map(encodeURIComponent).join("=")).join("&");

const params = {
  user: "María Rodríguez",
  awesome: true,
  awesomeness: 64,
  "ZOMG+&=*(": "*^%*GMOZ"
};

console.log("https://example.com/endpoint?" + encodeGetParams(params))


这在我的情况下非常有效,我在map函数中添加了一个decodeURIComponent调用,以确保已编码的条目不会混乱。 - Herbert Pimentel

30

使用URLSearchParams

const params = new URLSearchParams()
params.set('imageurl', 'http://www.image.com/?username=unknown&password=unknown')
return `http://www.foobar.com/foo?${params.toString()}`

这个在所有浏览器和浏览器版本中都能工作吗? - PlsWork
@PlsWork:虽然这是一个标准,但一些不到1%的浏览器尚未实现它:https://caniuse.com/urlsearchparams - serv-inc
1
为什么不使用整个URL API,并以 const url = new URL("http://www.foobar.com/foo"); 开始呢?此外,在大多数情况下,您需要 set,而不是 appendurl.set("imageurl", "http://www.image.com/?username=unknown&password=unknown"); return url; - Sebastian Simon
@SebastianSimon:关于set和append的观点很好,谢谢。使用URL可能会分散注意力,因为设置参数似乎不太优雅。或者我有所忽略吗? - serv-inc
1
@serv-inc 这取决于具体的使用情况;使用 URL 本身只是一个一般性的建议。我更喜欢通过 URL API 对我的 URL 进行验证,即使它们是静态的,所以这可能有点过度杀伤力;这只是个人偏好。 - Sebastian Simon
1
或者简单地说:http://foobar.com/foo?${new URLSearchParams({ imageurl: '...' }).toString()} - undefined

10

试着自己使用 encodeURI()encodeURIComponent() 函数...

console.log(encodeURIComponent('@#$%^&*'));

输入:@#$%^&*。输出:%40%23%24%25%5E%26*。那么,*发生了什么?为什么没有被转换?简而言之:根据MDN文档,您实际上需要使用fixedEncodeURIComponent()fixedEncodeURI(),而不是encodeURIComponent()encodeURI()。长话短说...
您不应该使用encodeURIComponent()encodeURI()。您应该使用fixedEncodeURIComponent()fixedEncodeURI(),根据MDN文档。
关于encodeURI()...

如果希望遵循更近期的RFC3986用于URL的规范,该规范使方括号保留(用于IPv6),因此在形成可能是URL的一部分的内容时不会对其进行编码(例如主机),则以下代码段可能会有所帮助:

function fixedEncodeURI(str) { return encodeURI(str).replace(/%5B/g, '[').replace(/%5D/g, ']'); }

关于encodeURIComponent()...

为了更严格地遵守RFC 3986(即使这些字符没有正式的URI分隔用途,但保留!,“,(),和*),可以安全地使用以下内容:

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

那么,有什么区别?fixedEncodeURI()fixedEncodeURIComponent()将相同的一组值转换,但fixedEncodeURIComponent()还会转换此集合:+@?=:*#;,$&。该集合用于GET参数(&+等),锚标签(#),通配符标签(*),电子邮件/用户名部分(@)等。
例如 -- 如果你使用 encodeURI() 函数,user@example.com/?email=me@home 将不能正确发送第二个 @ 到服务器,除非你的浏览器处理兼容性(如Chrome通常自然做)。

“除了您的浏览器处理兼容性之外”,这句话是什么意思? - Stephan
1
@Stephan:举例来说,如果site.com?formula=a+b=c可以生成formula=>a+b=c,那就违反了规范。但是如果它可以工作,这是因为Chrome等浏览器可以检测到URL的规范失败等问题,以及user@site.com?email=user@site.com等其他问题。 - HoldOffHunger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接