简体中文

开发者工具 · URL 编码器和解码器

文件下载链接中的空格:为什么 %20、+ 和原始空格不一样

· 为什么它很重要

url 编码 http 开发人员工作流程

下载文件名中空格的三种编码方式比较
原始 ToolAcre 矢量图

名为“Q3 报告(最终).pdf”的文件可以通过三种不同的方式链接,但只有一种是可靠正确的。这篇文章解释了为什么文件名会破坏下载链接以及如何对其进行编码以便每个客户都同意。

下载对某些用户失败但对其他用户有效 - 文件名带有空格和加号

像“Q3 report.pdf”这样的文件在本地存储时工作正常,但对于某些用户来说,通过下载链接会失败,而其他用户则可以成功。根据 RFC 3986 规范,原始空格在 URL 中无效。浏览器允许它们出现在地址栏中,但 HTTP 客户端严格拒绝它们。了解 %20、加号和原始空格对于可靠的分发绝对重要。编码方法之间的区别直接影响全球不同平台、各种自动化工具和 HTTP 客户端实现的下载成功率。开发人员在构建下载系统时必须理解这种区别。上下文对于编码选择和系统兼容性很重要。

创建下载链接时,开发人员必须在原始空格、%20 或加号之间进行选择。使用curl、wget 和Python 进行测试可以揭示哪些客户端强制执行RFC 合规性。浏览器下载由于错误恢复而成功,但 API 集成在遇到未编码的空格时失败。

为什么 URL 中的原始空格无效 - 以及为什么浏览器可以容忍地址栏中的原始空格,但 HTTP 客户端却不能

URL 中的原始空格在协议设计中具有历史根源。 URL 遍历系统,将空格视为标记之间的分隔符。 URL 中的空格可能会被误解为其终止符。从命令行读取的 HTTP 客户端会在第一个空格处截断。这种基础设计仍然保留在协议实现中,并且不太可能改变。

浏览器在发送 HTTP 请求之前通过静默转换为 %20 来容忍原始空间。这种用户友好的行为隐藏了最终用户将 URL 粘贴到地址栏中的协议要求。自动化系统缺乏这个恢复层。脚本在带有原始空格的 URL 上失败。电子邮件客户端在打开此类链接时遇到失败。

%20 与路径段中的 + — 不适用于路径的表单编码约定

%20 与加号代表 URL 编码上下文中的根本区别。在路径段中,空格必须根据 RFC 3986 编码为 %20。加号不是路径中的空格编码。此约定起源于 HTML 表单编码,它用作查询字符串中的空间编码。开发人员经常错误地将表单规则应用于路径。

允许加号的表单编码约定不适用于具有不同结构要求的路径。在查询字符串中,“&”和“等于”分隔参数。对查询值中的空格使用加号不会产生歧义,因为加号不是分隔符。在路径中,plus 没有特殊含义。混合约定会创建损坏的下载链接。

非 ASCII 文件名 — UTF-8 百分比编码和存储原始名称的对象存储键

非 ASCII 文件名在 URL 中安全传输之前需要 UTF-8 百分比编码。像“Über report.pdf”这样的文件名包含超出 ASCII 范围的“Ü”(U+00DC)。 UTF-8 编码将其转换为字节 C3 9C。这些字节在 URL 中百分比编码为 %C3%9C。每个 UTF-8 字节都有自己的三元组,产生更长的编码文件名。

Amazon S3 等对象存储服务为非 ASCII 文件名提供了有趣的案例。某些系统允许密钥中使用原始 UTF-8 字节,而其他系统则需要百分比编码。编码策略取决于存储提供商和 URL 使用情况。基于 URL 的访问需要百分比编码的 UTF-8。开发人员必须协调存储层和 URL 生成层。

工作示例:为路径编码“Über Q3 报告(最终)+notes.pdf” — 确切的输出以及为什么 + 必须变为 %2B

工作示例:编码“Über report (final)+notes.pdf”演示了完整的编码。文件名包含空格、非 ASCII 字符和文字加号。 “Ü”的 UTF-8 编码生成 %C3%9C。在路径编码中,空格变为 %20 (与使用加号的形式编码不同)。文字加号变为 %2B。括号编码为 %28 和 %29。结果:%C3%9CberQ3%20report%20%28final%29%2Bnotes.pdf。

使用 URL 编码器和解码器进行测试显示了精确的转换。将文件名粘贴到单值模式中会使用路径规则生成正确的百分比编码段。该工具保留路径分隔符,同时仅对文件名组件进行编码。输入和输出的视觉比较使规则在生产前变得清晰且可验证。将其与表单模式进行比较以查看上下文差异。

Content-Disposition 和 filename* 参数 — 下载提示的单独编码,为了完整性而提及

Content-Disposition 和 filename* 参数表示下载提示的替代编码层。服务器包含 Content-Disposition 标头,指定下载对话框的文件名。 filename 参数使用 RFC 2183 编码,而 filename* 使用 RFC 5987 和百分比编码。浏览器解释这些标头来决定保存文件名称。相同的文件名使用不同的方案进行两次编码。

两个编码层会产生转码错误的机会。如果服务器和客户端不一致,URL 编码和标头编码的文件名可能无法正确往返。为了获得最大兼容性,开发人员应使用 %20 和 UTF-8 百分比编码对 URL 路径中的文件名进行编码,并使用解码后的文件名设置 Content-Disposition 标头。这可确保所有 HTTP 客户端和浏览器正常工作。

这不包括什么 - 特定操作系统上的保留文件名和存储提供商的怪癖

特定操作系统上的保留文件名增加了 URL 编码的复杂性。 Windows 为设备保留 CON、PRN 和 AUX 等名称。字面上名为“CON.pdf”的文件不能存在于 NTFS 上。 macOS 有命名约定和扩展属性规则。 Linux 区分大小写。有效的 URL 编码文件名对于某些系统上的存储可能无效。

存储提供商的怪癖增加了跨平台分发的复杂性。 Amazon S3 接受 UTF-8 键并且区分大小写。 Google Cloud Storage 的行为类似,但有其他限制。 Azure Blob 存储具有不同的字符规则。在 S3 上工作的文件名在 Azure 上可能会失败。架构师必须检查提供商文档并使用真实的非 ASCII 文件名进行测试。

要点:对段进行编码,而不是 URL — URL 编码器和解码器的单值模式如何生成路径安全的文件名

要点:对段进行编码,而不是 URL — URL 编码器和解码器单值模式生成路径安全的文件名。该工具接受原始文件名并生成百分比编码的段。这可以防止双重编码和混合上下文。使用单值模式可以避免平衡路径、查询和片段编码规则。生成的段可以安全地插入到 URL 中。

最佳实践对进入 URL 构造的文件名进行编码。不要假设浏览器可以解决编码问题。使用目标用户使用的实际 HTTP 客户端进行测试:curl、wget、Python、Java httplib 和浏览器获取 API。验证文件名能否在整个系统中往返。 URL编码器和解码器是确保正确性的起点。