处理含中文字符的 URL

1 为什么会出现“乱码”或崩溃?

  • URL 标准(RFC 3986)规定:除少数保留字符外,URL 只能包含 ASCII。中文属于 Unicode,因此必须先转换。
  • 如果直接把 https://example.com/路径/ 这样的字符串传给 URL(string:),Swift 会把它视为 非法,初始化直接返回 nil,后续网络请求也会失败。
  • 主机名部分(如 网址.中国)可以使用 IDN(Punycode)隐式转换;路径 / 查询 / 片段 不会自动转义,必须开发者处理。

2 Swift /Foundation 的行为细节

位置直接支持中文?需要开发者操作典型失败表现
scheme / host✅(自动转 Punycode)
path / query / fragment必须百分号编码URL(string:) == nil
URLComponents / URLQueryItem✅(自动做正确编码)建议使用

绝对语句:未编码的中文字符出现在路径、查询或片段里时,URL(string:) 一定 返回 nil,而不是“通常”。

3 安全构造 URL 的 3 个方法

// ✅ 方法 1:让系统帮你转义
let raw = "https://www.example.com/搜索?q=中文"
let encoded = raw.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let url = URL(string: encoded)!   // 一定成功
// ✅ 方法 2:URLComponents 适合拼接 Query
var comps = URLComponents(string: "https://www.example.com/搜索")!
comps.queryItems = [URLQueryItem(name: "q", value: "中文")
]
let url = comps.url!              // 已正确编码
// ✅ 方法 3:只编码 path
let path = "路径/子路径".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!
let url = URL(string: "https://example.com/\(path)")!
场景推荐字符集
path.urlPathAllowed
query key/value.urlQueryAllowed
fragment.urlFragmentAllowed

4 常见坑

  1. 双重编码

    • 调用两次 addingPercentEncoding 会把 % 再转义成 %25
    • 解决:只在“最终拼接”前调用一次,或依赖 URLComponents
  2. 手工拼接 Query

    • "q=\(value)" 如果 value& 会截断。
    • URLQueryItem 永不过错。
  3. 服务器端未解码

    • 有些后端接口期望收到 UTF-8 原文:确认后端是否已自动 percentDecode
  4. UIWebView/WKWebView 打开中文 URL

    • 同样先编码,或使用 URLRequest(url:) 传入已编码的 URL

5 测试与调试

import XCTestfunc testChineseURL() {let comps = URLComponents(string: "https://域名.中国/搜索")!XCTAssertNotNil(comps.url)          // host 已转 PunycodeXCTAssertEqual(comps.url!.absoluteString,"https://xn--ihq79i.xn--fiqs8s/%E6%90%9C%E7%B4%A2")
}
  • Xcode 网络抓包:在 Console 或 Charles 中确认最终请求的 URL。
  • Unit Test:固化编码逻辑,避免后期回归。

6 总结

  • 中文主机名:Foundation 会自动 Punycode,无需关心。
  • 路径 / 查询 / 片段必须 百分号编码,否则 Swift 一定失败。
  • 最佳实践URLComponents + URLQueryItem,让系统帮你一次性处理所有细节。
  • 按照上面的套路,任何含中文字符的 URL 在 Swift 中都能被安全、稳定地使用。

by 侯仕奇 | sqi.io

所以最简单直接的方法就是严格规定:URL 中不允许使用中文 ?

可以,但你要知道这是「团队约定」,不是网络协议要求

做法优点明确缺点
硬性规定:所有接口只接受 ASCII(即先手动转义)- 团队心智负担最低
- 服务器端解析简单,不用担心不同语言框架的容错
- 可读性差,日志里全是 %E6%B5%8B%E8%AF%95
- SEO / 分享链接体验变差
- 第三方跳转(微信、微博等)容易出现两次转义或未转义问题
允许中文,但入口统一做一次 percent‐encode(推荐)- 代码可读(/搜索?q=中文
- 外部 copy-paste 时肉眼友好
- 仍然保证传输符合 RFC 3986
- 需要在 SDK 或 API Gateway 层加一段轻量工具方法
- 需要写单元测试防止误双重转义

为什么“完全禁用中文”并不总是最佳

  1. 现代浏览器与搜索引擎本来就支持 Unicode URL;直接禁用会牺牲人类可读性。
  2. 移动端分享体验:用户复制的往往是裸中文 URL,如果后台 400,用户体验会受损。
  3. 多语言产品:电商、文档类站点需要保留自然语言 slug(/产品/苹果手机)提升可维护性。

推荐落地方案

extension String {/// 将任何路径或查询中的非 ASCII 部分一次性安全转义func urlEncodedPath() -> String {addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!}
}// ⚙️ 统一在网络层 (e.g. APIClient) 使用
func makeRequest(path: String, query: [String: String] = [:]) -> URLRequest {var comps = URLComponents()comps.scheme = "https"comps.host   = "example.com"comps.percentEncodedPath = path.urlEncodedPath()comps.queryItems = query.map { URLQueryItem(name: $0.key, value: $0.value) }return URLRequest(url: comps.url!)
}
  • 任何进入网络层的字符串都可含中文
  • 网络层保证 encode 一次且仅一次
  • 服务器端:若使用现代框架(Node/Go/Java/Spring)通常会自动解码 %xx,无需额外处理。

结论:

  • 若团队小、接口固定,强行禁止中文确实最省事,但长期会降低可维护性。
  • 更稳健的做法是允许中文输入 → 统一转义 → 所有链路都用合法 ASCII URL 传输
  • 不管选哪条路,关键在于「入口唯一化」:只让一个地方负责转义/解码,就不会踩坑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/86718.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86718.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/86718.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

结构体字段能否单独加 mut

你问的这个问题在 Rust 里很常见: 一、结构体字段能否单独加 mut 1. 结构体字段能否单独加 mut? 不能。Rust 中,mut 是用来修饰变量绑定的,可变性是绑定的属性,而不是结构体字段本身的属性。 你不能写: …

scGPT-spatial 复现

文章目录 ✅ 总体流程总览(从 H5AD 到模型训练)🔧 步骤 1:读取 H5AD 文件并做基础预处理🧱 步骤 2:构造训练样本输入(token、value)📦 步骤 3:使用 DataColla…

运放电压跟随器为什么要加电阻

运放电压跟随器为什么要加电阻 我们常见运放的电压跟随器如下: 有时候会看见电路中加两个电阻: 作用就是保护运放,起限流电阻的作用。 当输入电压高的时候,运放内部存在钳位二极管,此电阻就能限流。 并不是所有运放…

MinerU 2.0部署

简介 MinerU 2.0使用sglang加速,与之前差别较大,建议按照官方的Docker镜像的方式启动。 Docker镜像 Dockerfile 这是官方的Dockerfile # Use the official sglang image FROM lmsysorg/sglang:v0.4.7-cu124# install mineru latest RUN python3 -m …

黑马python(十七)

目录: 1.数据可视化-地图-基础案例 2.全国疫情地图 3.河南省疫情地图绘制 4.基础柱状图构建 5.基础时间线柱状图绘制 6.动态GDP柱状图绘制 1.数据可视化-地图-基础案例 图示有点对的不准,可以通过后面的参数 2.全国疫情地图 3.河南省疫情地图绘制…

Segment Anything in High Quality之SAM-HQ论文阅读

摘要 最近的 Segment Anything Model(SAM)在扩展分割模型规模方面取得了重大突破,具备强大的零样本能力和灵活的提示机制。尽管 SAM 在训练时使用了 11 亿个掩码,其掩码预测质量在许多情况下仍不理想,尤其是对于结构复杂的目标。我们提出了 HQ-SAM,使 SAM 能够精确地分割…

深入理解_FreeRTOS的内部实现(2)

1.事件组 事件组结构体: 事件组 “不关中断” 的核心逻辑 事件组操作时,优先选择 “关调度器” 而非 “关中断” ,原因和实现如下: 关调度器(而非关中断) FreeRTOS 提供 taskENTER_CRITICAL()(…

【图论题典】Swift 解 LeetCode 最小高度树:中心剥离法详解

文章目录 摘要描述题解答案题解代码分析思路来源:树的“中心剥离法”构造邻接表和度数组循环剥叶子终止条件 示例测试及结果时间复杂度空间复杂度总结 摘要 树是一种重要的数据结构,在许多应用里,我们希望选一个根,让这棵树的高度…

Docker的介绍与安装

​ Docker 对初学者的简单解释和应用场景 1.什么是 Docker? 简单来说,Docker 就像一个“装箱子”的工具,这个箱子叫做“容器”。 你写的程序和它运行需要的环境(比如操作系统、软件、工具)都装进一个箱子里。这个箱…

引导相机:工业自动化的智能之眼,赋能制造业高效升级

在工业自动化浪潮中,精准的视觉引导技术正成为生产效率跃升的关键。作为迁移科技——一家成立于2017年、专注于3D工业相机和3D视觉系统的领先供应商,我们深知"引导相机"的核心价值:它不仅是一个硬件设备,更是连接物理世…

智能相机如何重塑工业自动化?迁移科技3D视觉系统的场景革命

从硬件参数到产业价值,解码高精度视觉系统的落地逻辑 一、工业视觉的“智慧之眼” 迁移科技深耕3D工业相机领域,以“稳定、易用、高回报”为核心理念,打造覆盖硬件、算法、软件的全栈式视觉系统。成立6年累计融资数亿元的背后,是…

【数据挖掘】聚类算法学习—K-Means

K-Means K-Means是一种经典的无监督学习算法,用于将数据集划分为K个簇(clusters),使得同一簇内的数据点相似度高,不同簇间的相似度低。它在数据挖掘、模式识别和机器学习中广泛应用,如客户细分、图像压缩和…

linux环境内存满php-fpm

检查 PHP-FPM 配置 pm.max_children:该参数控制 PHP-FPM 进程池中最大允许的子进程数。过高的子进程数会导致内存占用过大。你可以根据服务器的内存大小来调整 pm.start_servers:控制 PHP-FPM 启动时创建的进程数。根据实际情况调整此值。 pm.min_spare_…

基于CNN卷积神经网络图像识别小程序9部合集

基于CNN卷积神经网络图像识别小程序合集-视频介绍下自取 ​ 内容包括: 基于python深度学习的水果或其他物体识别小程序 003基于python深度学习的水果或其他物体识别小程序_哔哩哔哩_bilibili 代码使用的是python环境pytorch深度学习框架,代码的环境安…

WebRTC(九):JitterBuffer

JitterBuffer Jitter “Jitter”指的是连续到达的媒体包之间时间间隔的变化。在网络传输中,由于: 网络拥塞路由路径变化队列排队不同链路带宽差异 导致包之间的接收时间不一致,这就是网络“抖动”。 作用 **JitterBuffer(抖…

【推荐100个unity插件】在 Unity 中绘制 3D 常春藤,模拟生长——hedera插件的使用

注意:考虑到后续接触的插件会越来越多,我将插件相关的内容单独分开,并全部整合放在【推荐100个unity插件】专栏里,感兴趣的小伙伴可以前往逐一查看学习。 效果演示 文章目录 效果演示前言一、常春藤生成器工具下载二、工具使用1、…

【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之高斯椭球的几何变换

【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之高斯椭球的几何变换 文章目录 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之高斯椭球的几何变换前言模型变换(Model Transformation)观测变换(Viewing Transformation)视图变换(View Transformation)投影…

EXISTS 和 NOT EXISTS 、IN (和 NOT IN)

在 SQL 中,EXISTS、NOT EXISTS 和 IN 都是用于子查询的条件运算符,用于根据子查询的结果过滤主查询的行。它们之间的区别主要体现在工作方式、效率、对 NULL 值的处理以及适用场景上。 1. EXISTS 和 NOT EXISTS 作用: EXISTS: 检查子查询是…

GitHub 趋势日报 (2025年06月25日)

📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 880 awesome 788 build-your-own-x 691 free-for-dev 427 best-of-ml-python 404 …

互联网大厂Java求职面试:Java虚拟线程实战

互联网大厂Java求职面试:Java虚拟线程实战 文章内容 开篇:技术总监与程序员郑薪苦的三轮对话 在一场紧张而严肃的Java工程师面试中,技术总监张工正对候选人郑薪苦进行深入提问。郑薪苦虽然性格幽默,但对技术有着扎实的理解。今天…