外部链接网址编码会导致'%3F'和'%3D'%在Nginx服务器上

时间:2013-12-09 12:03:39

标签: nginx rewrite external-links

我的服务器出了问题。我有四个到动态网页不同网站的入站链接,如下所示:

myurl.com/default/Site%3Fid%3D13

他们应该是这样的:

myurl.com/default/Site?id=13

我知道那些%3F?符号的转义序列,%3D是等号的转义序列。但是当我使用这些链接时,我确实收到错误400。我该怎么办?

这四个链接适用于不同的网站,我想随着时间的推移会有更多这样的链接。因此,对所有人的一个解决方案将是完美的。

3 个答案:

答案 0 :(得分:8)

大约一年前,nginx-ru邮件列表上确实提出了一个完全相同的问题:

http://mailman.nginx.org/pipermail/nginx-ru/2013-February/050200.html

最有帮助的回应,由Nginx,Inc,员工/开发人员,ВалентинБартенев:

http://mailman.nginx.org/pipermail/nginx-ru/2013-February/050209.html

  

Еслизапросприходитвтакомвиде,тоэтоуженепараметры,аимязапрошенного   файла。 Другоедело,чтоlocationищетсяпоужераскодированномуадресу,очемв   документациинаписано。

翻译:

  

如果请求以这种形式出现,那么这些不再是args,而是请求文件的名称。另一件事是,如文档所述,位置匹配是针对规范化的URI执行的。

他建议的解决方案,从SO的问题翻译成示例,然后是:

location /default/Site? {
    rewrite \?(.*)$ /default/Site?$1? last;
}

location = /default/Site {
    [...]
}

答案 1 :(得分:1)

以下示例将重定向所有看似错误的请求(在请求的文件名中定义为? - 在请求中编码为%3F),不管URL如何,都会重定向到看起来不那么错误的请求。 / p>

(请注意,正如在其他地方正确建议的那样,您不应该首先获得这些错误形成的链接,因此,将其作为最后手段使用 - 只有当您无法纠正错误形成的链接时,否则,请注意,有效代理会尝试此类请求。)

server {
    listen      [::]:80;
    server_name localhost;

    rewrite     ^/([^?]*)\?(.*)$    /$1?$2?     permanent;
    location / {
        return  200 "id is $arg_id\n";
    }
}

这是它如何工作的示例 - 当遇到错误查看的请求时,使用301 Moved Permanently响应进行更正尝试,并使用假定正确的Location响应标头,这将使浏览器成为可能自动将请求重新发送到新提供的位置:

opti# curl -6v "http://localhost/default/Site%3Fid%3D13"
* About to connect() to localhost port 80 (#0)
*   Trying ::1...
* connected
* Connected to localhost (::1) port 80 (#0)
> GET /default/Site%3Fid%3D13 HTTP/1.1
> User-Agent: curl/7.26.0
> Host: localhost
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.4.1
< Date: Wed, 15 Jan 2014 17:09:25 GMT
< Content-Type: text/html
< Content-Length: 184
< Location: http://localhost/default/Site?id=13
< Connection: keep-alive
<
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.4.1</center>
</body>
</html>
* Connection #0 to host localhost left intact
* Closing connection #0

请注意,不会对正确的请求进行更正尝试:

opti# curl -6v "http://localhost/default/Site?id=13"
* About to connect() to localhost port 80 (#0)
*   Trying ::1...
* connected
* Connected to localhost (::1) port 80 (#0)
> GET /default/Site?id=13 HTTP/1.1
> User-Agent: curl/7.26.0
> Host: localhost
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.4.1
< Date: Wed, 15 Jan 2014 17:09:30 GMT
< Content-Type: application/octet-stream
< Content-Length: 9
< Connection: keep-alive
<
id is 13
* Connection #0 to host localhost left intact
* Closing connection #0

答案 2 :(得分:0)

URL完全有效。它包含的转义字符只是逃脱的。这完全没问题。

目的是你实际上可以有一个请求名称(在大多数情况下对应于磁盘上的文件名)Site?id=13而不是Site,其余的作为查询字符串。

我认为在文件名中包含字符会使这一点成为必要,这是不好的做法。但是,在URL参数中,它可能是必要的。

然而,请求URL是有效的,可能不是您想要的。因此,建议您在任何人首先获取错误的URL时纠正错误。

我真的不明白为什么你会收到错误400;你应该得到一个错误404.但这取决于你的设置。

还有一些情况,特别是对于nginx,主要涉及沿多个级别传递整个URL和URL部分(例如反向代理,匹配URL中的正则表达式并将它们用作变量等),这样的错误可能导致。但要验证并修复它,我们需要了解有关您的设置的更多信息。