杰瑞科技汇

Python unquote 空格会被正确处理吗?

在 Python 中,处理 URL 编码字符串中的空格时,需要区分 URL 编码的空格实际的空格字符

Python unquote 空格会被正确处理吗?-图1
(图片来源网络,侵删)
  1. urllib.parse.unquote 的作用:它只解码 %20 这种形式的 URL 编码,它不会把普通的空格字符()转换成 号,也不会把 号转换成空格。
  2. urllib.parse.unquote_plus 的作用:这是处理表单数据(特别是 application/x-www-form-urlencoded 格式)的正确函数,它会:
    • %20 解码成空格。
    • 将 号解码成空格。
  3. 最佳实践
    • 如果你在处理一个完整的 URL(从浏览器地址栏复制来的),使用 unquote
    • 如果你在处理一个来自 HTML 表单 POST 请求的查询参数(request.bodyrequest.get_data()),必须使用 unquote_plus

详细解释与代码示例

urllib.parse.unquote

这个函数是 URL 解码的标准实现,它遵循 RFC 3986 标准,在这个标准中,空格被编码为 %20

行为

  • %20 转换为空格 。
  • 对其他 %XX 形式的编码进行解码。
  • 对普通空格 和 号不做任何处理

示例

from urllib.parse import unquote
# 场景1: 标准URL编码,空格是 %20
url_encoded_with_percent20 = "Hello%20World%21"
decoded_unquote = unquote(url_encoded_with_percent20)
print(f"原始字符串: {url_encoded_with_percent20}")
print(f"unquote 解码后: {decoded_unquote}")
# 输出:
# 原始字符串: Hello%20World%21
# unquote 解码后: Hello World!
print("-" * 20)
# 场景2: 字符串中包含普通空格
url_with_space = "Hello World"
decoded_with_space = unquote(url_with_space)
print(f"原始字符串: {url_with_space}")
print(f"unquote 解码后: {decoded_with_space}")
# 输出:
# 原始字符串: Hello World
# unquote 解码后: Hello World (空格保持不变)
print("-" * 20)
# 场景3: 字符串中包含 + 号
url_with_plus = "Hello+World"
decoded_with_plus = unquote(url_with_plus)
print(f"原始字符串: {url_with_plus}")
print(f"unquote 解码后: {decoded_with_plus}")
# 输出:
# 原始字符串: Hello+World
# unquote 解码后: Hello+World (+号保持不变)

urllib.parse.unquote_plus

这个函数专门用于处理 application/x-www-form-urlencoded 这种常见的表单提交格式,在这种格式中,为了方便,空格经常被编码成 号。

Python unquote 空格会被正确处理吗?-图2
(图片来源网络,侵删)

行为

  • %20 转换为空格 。
  • 将 号也转换为空格 。
  • 对其他 %XX 形式的编码进行解码。

示例

from urllib.parse import unquote_plus
# 场景1: 标准URL编码,空格是 %20
url_encoded_with_percent20 = "Hello%20World%21"
decoded_plus_1 = unquote_plus(url_encoded_with_percent20)
print(f"原始字符串: {url_encoded_with_percent20}")
print(f"unquote_plus 解码后: {decoded_plus_1}")
# 输出:
# 原始字符串: Hello%20World%21
# unquote_plus 解码后: Hello World!
print("-" * 20)
# 场景2: 表单格式编码,空格是 +
url_encoded_with_plus = "name=John+Doe&message=Hello+World"
decoded_plus_2 = unquote_plus(url_encoded_with_plus)
print(f"原始字符串: {url_encoded_with_plus}")
print(f"unquote_plus 解码后: {decoded_plus_2}")
# 输出:
# 原始字符串: name=John+Doe&message=Hello+World
# unquote_plus 解码后: name=John Doe&message=Hello World
# 注意:+ 被正确地转换成了空格
print("-" * 20)
# 场景3: 混合了 %20 和 +
url_mixed = "search=python%20tutorial+for+beginners"
decoded_plus_3 = unquote_plus(url_mixed)
print(f"原始字符串: {url_mixed}")
print(f"unquote_plus 解码后: {decoded_plus_3}")
# 输出:
# 原始字符串: search=python%20tutorial+for+beginners
# unquote_plus 解码后: search=python tutorial for beginners
# %20 和 + 都被正确地转换成了空格

在 Web 框架中的实际应用

当你使用 Flask 或 Django 等 Web 框架时,这个问题会经常出现。

Flask 示例

假设你有一个前端表单,用户输入 "John Doe"。

HTML Form:

<form action="/submit" method="post">
  <input type="text" name="username" value="John Doe">
  <button type="submit">Submit</button>
</form>

当这个表单被 POST 提交时,请求体中的数据会被编码为 application/x-www-form-urlencoded 格式,浏览器可能会发送 username=John+Doeusername=John%20Doe

Flask 后端处理:

from flask import Flask, request
from urllib.parse import unquote, unquote_plus
app = Flask(__name__)
@app.route('/submit', methods=['POST'])
def submit():
    # request.get_data() 获取原始的请求体
    raw_body = request.get_data(as_text=True)
    print(f"原始请求体: {raw_body}")
    # --- 错误的做法 ---
    # 如果使用 unquote,+ 号不会被解码,可能导致问题
    # decoded_wrong = unquote(raw_body)
    # username_wrong = decoded_wrong.split('=')[1]
    # print(f"错误解码后的用户名: {username_wrong}") # 可能是 "John+Doe"
    # --- 正确的做法 ---
    # 对于 form data,应该使用 unquote_plus
    decoded_correct = unquote_plus(raw_body)
    username_correct = decoded_correct.split('=')[1]
    print(f"正确解码后的用户名: {username_correct}")
    return f"你好, {username_correct}!"
if __name__ == '__main__':
    app.run(debug=True)

当你提交表单后,服务器日志会显示:

原始请求体: username=John+Doe
正确解码后的用户名: John Doe

如果你错误地使用了 unquote,你可能会得到 "John+Doe" 这样的结果,这不是你想要的。

函数 处理 %20 处理 主要用途
unquote 转换成空格 不做处理 解码完整的 URL 字符串(如 URL 路径、查询参数中的值)
unquote_plus 转换成空格 转换成空格 解码表单数据(application/x-www-form-urlencoded

记住这个关键区别,你就能正确处理 URL 中的空格了。

分享:
扫描分享到社交APP
上一篇
下一篇