Параметры URL-адреса Flask с% не обрабатываются должным образом

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)

Ex.

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, параметр равен " " в конце функции вместо "%20", в начале функции он равен "%20", а не "%2520".

В настоящее время я работаю над приложением Flask, используя Python 2.7.

Я пытаюсь создать функцию, которая может обрабатывать параметры 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" должно быть "foo%20bar".

Из-за этой ошибки я не могу удалить запись "foo%20bar". Если я попытаюсь удалить его, он удалит "foo bar", а после удаления "foo bar" запись "foo%20bar" уже никогда не будет удалена.

Я считаю, что это потому, что "%20" не равно "%2520", хотя это и есть параметр. Когда я печатаю это значение перед вызовом urllib.unquote(param), оно уже равно "%20". Затем, когда я вызываю urllib.unquote(param), значение изменяется на " ".

Я не совсем уверен, что это ошибка в Flask/Werkzeug, но из-за нее мое приложение не работает.

Есть ли у вас какие-либо предложения по устранению этой проблемы? Спасибо!


person Daniel    schedule 19.03.2019    source источник
comment
Нет, foo%20bar является foo bar. Даже foo bar в адресной строке браузера фактически отправляется на сервер как foo%20bar. Если вы действительно хотели foo%20bar после декодирования URL, отправьте foo%2520bar.   -  person Martijn Pieters    schedule 19.03.2019
comment
Извиняюсь. Я, должно быть, был неясен. "foo%2520bar" равно "foo%20bar" ДО того, как я изменю значение с помощью urllib.unquote. Поэтому, если я вызову /v1/foo%2520bar, значение параметра будет равно "foo bar" вместо "foo%20bar" @MartijnPieters   -  person Daniel    schedule 19.03.2019
comment
Так почему же вы тогда вообще используете urllib.unquote()?   -  person Martijn Pieters    schedule 19.03.2019
comment
@MartijnPieters Я буду передавать URL-адреса в параметр.   -  person Daniel    schedule 19.03.2019


Ответы (2)


Нет, 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). Вам нужно будет использовать компонент <path:param>, чтобы соответствовать им, потому что тип параметра 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: {urllib.parse.unquote(param)}\n",
        200,
        {'content-type': 'text/plain'}
    )

используйте FLASK_APP=routetest flask run для запуска этого скрипта на localhost: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, который неправильно обрабатывает кавычки в путях.

person Martijn Pieters    schedule 19.03.2019
comment
Мне нужно изменить параметр. Это потому, что я передаю URL-адреса этой конечной точке в своем интерфейсе. - person Daniel; 19.03.2019
comment
@ Даниэль: так? Это не требует двойного декодирования. - person Martijn Pieters; 19.03.2019
comment
Борюсь с этим багом уже день. Я кодирую параметр на интерфейсе. Я передаю его на бэкэнд. Я считаю, что фляга декодирует для меня параметр IN PART. В этом проблема. %2F по-прежнему %2F. Он не превращается в /. - person Daniel; 19.03.2019
comment
@Daniel: Тогда я предлагаю вам предоставить нам правильный MCVE, который воспроизводит вашу настоящую проблему. Сейчас все, что у нас есть, это частичный диагноз от вас, и он неверен. - person Martijn Pieters; 19.03.2019
comment
Я сожалею, что я не был ясен. Я обновил свой пост. Спасибо, что помогли мне с этим и проявили терпение. - person Daniel; 19.03.2019
comment
@Daniel: да, в этом случае вам нужно использовать <path:param>, а не <param>. - person Martijn Pieters; 19.03.2019
comment
@Daniel: и я не могу воспроизвести проблему со встроенным сервером WSGI, поэтому у вас есть сервер WSGI, который вызывает это, а не сам Flask. - person Martijn Pieters; 19.03.2019
comment
Это все еще не работает для меня. Если в параметре есть https://, я получаю ошибку 404. Если в параметре есть %2520, он преобразуется в пробел вместо %20. - person Daniel; 19.03.2019
comment
@Daniel: я показал вам четкий воспроизводимый тест. Это не Flask или Werkzeug, это ваш сервер WSGI. - person Martijn Pieters; 19.03.2019
comment
Ой. Большое спасибо! Извините, я не заметил, что вы обновили это. - person Daniel; 19.03.2019
comment
Интересно, есть ли какие-либо изменения в Flask в последнее время? Мое приложение Flask недавно сломалось, потому что оно не декодирует %20 в пробел автоматически, мне нужно использовать urllib.unquote сейчас. - person stenlytw; 08.08.2020
comment
@stenlytw Нет, там ничего не изменилось. Вы уверены, что значение не было дважды закодировано? - person Martijn Pieters; 08.08.2020