带有%的Flask URL参数处理不正确

问题描述:

EDIT2:对于不清晰,我深表歉意。
我将提供几个值。第一个是我使用前端应用程序调用的URL。第二个是调用 urllib.unquote 之前的值。第三个是调用 urlib.unquote 之后的值。

I apologize for the lack of clarity. I will provide several values. The first is the URL that I call using my frontend app. The second is the value before calling urllib.unquote. The third is the value after calling urlib.unquote.

前端:

console.log('http://localhost:8080/v1/' + encodeURIComponent(name))

后端:

def f(param=''):
    print('*', param)
    param = urllib.unquote(param)
    print('**', param)

例如。

http://localhost:8080/v1/https%3A%2F%2Fgoogle.com
* https:%2F%2Fgoogle.com
** https://google.com

Ex2。

http://localhost:8080/v1/foo%2520bar
* foo%20bar
** foo bar

Ex3。

http://localhost:8080/v1/foo%20bar
* foo bar
** foo bar

感谢您耐心等待并帮助我。抱歉,我在原始帖子中不清楚。

Thank you for being patient and helping me with this. I apologize for being unclear in my original post.

编辑:简而言之,如果我拨打 / v1 /%2520 ,参数在函数末尾等于 ,而不是%20 函数的开头等于%20 而不是%2520

In short, if I call /v1/%2520, param is equal to " " at the end of the function, instead of "%20", at the beginning of the function it is equal to "%20" and not "%2520".

我目前正在使用Python 2.7开发Flask应用程序。

I'm currently working on a Flask App using Python 2.7.

我正在尝试创建一个可以处理URL的函数

I'm trying to create a function which can handle URL parameters.

@app.route('/v1/<param>', methods=['DELETE'])
def f(param=''):
    param = urllib.unquote(param)

在前端应用程序中,我通过对 param 进行编码来调用此函数。但是,如果我将 foo bar foo%20bar 传递给函数,则 param 解析为相同的值- foo bar ,而实际上是 foo bar 应该为 foo bar foo%20bar 应该为 foo%20bar

On my frontend application, I call this function by encoding the param. However, if I pass "foo bar" and "foo%20bar" to the function, the param is resolved to the same value -- "foo bar", when really "foo bar" should be "foo bar" and "foo%20bar" should be "foo%20bar".

由于此错误,我无法删除 foo%20bar 条目。如果我尝试删除它,它将删除 foo bar ,并且一旦删除 foo bar foo%20bar 条目将永远不会被删除。

Due to this bug, I am unable to delete the "foo%20bar" entry. If I try to delete it, it will delete "foo bar", and once "foo bar" is deleted, the "foo%20bar"entry will never be deleted.

我相信这是因为%20 不等于%2520 ,尽管这就是参数。当我在调用 urllib.unquote(param)之前打印此值时,它已经等于%20 。然后,当我调用 urllib.unquote(param)时,该值将更改为 $ c>。

I believe this is because "%20" is not equal to "%2520" even though that is what the param is. When I print this value before calling urllib.unquote(param) it is already equal to "%20". Then, when I call urllib.unquote(param) the value is changed to " ".

我不确定这是否是Flask / Werkzeug中的错误,但这导致我的应用程序无法正常工作。

I'm not really sure if this is a bug in Flask/Werkzeug, but it is causing my application to not work.

您对解决此问题有任何建议吗?谢谢!

Do you have any suggestions for fixing this issue? Thanks!

不,Flask通常会处理百分比编码的完全正确。 URL中的参数是百分比编码的,并且在设置WSGI环境时会为您解码这些参数。匹配时,Flask会将其传递到您的路线。

No, Flask is usually handling percent encoding exactly right. Parameters in a URL are percent encoded, and these are decoded for you when the WSGI environment is set up. Flask then passes this on to your route when matching.

不需要不需要再次解码参数值,请删除您的 urllib.unquote()调用。

You do not need to decode the parameter value again, remove your urllib.unquote() call.

您的浏览器实际上会将URL中的空格编码为%20 ,即使位置栏上会显示一个空格。位置栏可对百分比编码的组件进行解码,从而可以读取国际字符(因此%E3%81%A9%E3%81%86%E3%82%82%E3%81%82%E3例如,%82%8A%E3%81%8C%E3%81%A8%E3%81%86 显示为どうもありがとう )。

Your browser will actually encode spaces in the URL to %20 for you, even though the location bar will show a space. The location bar decodes percent-encoded components to make it possible to read international characters (so %E3%81%A9%E3%81%86%E3%82%82%E3%81%82%E3%82%8A%E3%81%8C%E3%81%A8%E3%81%86 is shown as どうもありがとう, for example).

如果您遇到编码斜杠( / %2F ),然后参见 issue#900 ,其中有一些极端情况与Apache指令(和其他WSGI服务器)一起考虑。您需要使用< path:param> 组件来匹配它们,因为默认的 string 参数类型将不匹配斜杠。

If you are having issues with encoded slashes (/, %2F), then see issue #900, there are edge cases with Apache directives (and other WSGI servers) to consider. You would need to use a <path:param> component to match those, because the default string parameter type will not match slashes.

如果我使用以下测试脚本,命名为 routetest.py

If I use the following test script, named routetest.py:

from flask import Flask
try:
    from urllib.parse import unquote  # PY3
except ImportError:
    from urllib import unquote  # PY2

app = Flask(__name__)

@app.route('/v1/<path:param>')  # NOTE: <path:param> is required to match /
def f(param=''):
    return (
        f"param: {param}\ndecoded param: {urllib.parse.unquote(param)}\n",
        200,
        {'content-type': 'text/plain'}
    )

使用 FLASK_APP = routetest flask run localhost:5000 上启动此脚本>,那么我无法重现您的问题:

use FLASK_APP=routetest flask run to launch this script on localhost:5000, then I can't reproduce your issues:

$ curl http://localhost:5000/v1/https%3A%2F%2Fgoogle.com
param: https://google.com
decoded param: https://google.com
$ curl http://localhost:5000/v1/foo%2520bar
param: foo%20bar
decoded param: foo bar
$ curl http://localhost:5000/v1/foo%20bar
param: foo bar
decoded param: foo bar

这仅意味着您拥有错误处理引用的WSGI服务器路径。

which can only mean that you have a WSGI server that is mishandling quoting in paths.