【问题标题】:Flask URL Parameters with % Are Not Properly Handled带有 % 的 Flask URL 参数未正确处理
【发布时间】:2019-03-19 17:04:16
【问题描述】:

EDIT2:我为缺乏明确性表示歉意。 我将提供几个值。第一个是我使用前端应用程序调用的 URL。第二个是调用urllib.unquote之前的值。第三个是调用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

感谢您耐心等待并帮助我解决此问题。我很抱歉在我的原始帖子中不清楚。

编辑:简而言之,如果我调用/v1/%2520,param 在函数末尾等于" ",而不是"%20",在函数开头它等于"%20" 而不是"%2520".

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

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

@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" 应该是@987654342 @。

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

我相信这是因为"%20" 不等于"%2520",即使那是参数。当我在调用urllib.unquote(param) 之前打印此值时,它已经等于"%20"。然后,当我调用urllib.unquote(param) 时,值将更改为" "

我不确定这是否是 Flask/Werkzeug 中的错误,但它会导致我的应用程序无法运行。

您对解决此问题有什么建议吗?谢谢!

【问题讨论】:

  • 不,foo%20bar foo bar。甚至浏览器 URL 栏中的foo bar 实际上也是作为foo%20bar 发送到服务器的。如果你真的想要 URL 解码后的foo%20bar,那么发送foo%2520bar
  • 对不起。我一定是不清楚。在我使用 urllib.unquote 修改值之前,"foo%2520bar" 等于 "foo%20bar"。所以如果我调用/v1/foo%2520bar,参数值等于"foo bar"而不是"foo%20bar"@MartijnPieters
  • 那你为什么还要使用urllib.unquote()呢?
  • @MartijnPieters 我会将 URL 传递给参数。

标签: python url flask encoding werkzeug


【解决方案1】:

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

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

您的浏览器实际上会为您将 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 显示为 どうもありがとう)。

如果您遇到编码斜杠(/%2F)的问题,请参阅issue #900,需要考虑 Apache 指令(和其他 WSGI 服务器)的边缘情况。您需要使用 &lt;path:param&gt; 组件来匹配它们,因为默认的 string 参数类型不会匹配斜杠。

如果我使用以下名为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: {unquote(param)}\n",
        200,
        {'content-type': 'text/plain'}
    )

使用FLASK_APP=routetest flask runlocalhost:5000 上启动此脚本,然后我无法重现您的问题:

$ 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 服务器错误地处理了路径中的引用。

【讨论】:

    【解决方案2】:

    我认为问题在于您不了解 URL 编码 :) 它需要避免空格,所以它们被浏览器翻译成 %20 并被烧瓶自动翻译回来。 阅读本文了解更多信息:https://www.w3schools.com/tags/ref_urlencode.asp

    解决方案:将编码的foo%20bar 发送到带有foo%2520bar 的服务器。

    【讨论】:

    • 对不起,我不清楚。我更新了我的问题。为方便起见,编辑:简而言之,如果我调用 /v1/%2520,param 等于函数末尾的“”,而不是“%20”
    • 不知道最近Flask有什么变化吗?我的 Flask 应用最近坏了,因为它不会自动将 %20 解码为空间,我现在需要使用 urllib.unquote
    猜你喜欢
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    • 2019-02-12
    相关资源
    最近更新 更多