You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS开发中URLComponents查询参数内@符号未编码的解决方法问询

iOS 中 URLComponents 实现查询参数@正确编码的方案

问题本质

  • 系统默认URLComponents的参数转义逻辑遵循RFC 3986宽松规则,@属于URL查询段内允许直接保留的合法字符,默认不会做转义处理。
  • Alamofire 采用更严格的查询值转义策略,会把所有不属于查询分隔符的特殊字符(包括@)统一编码,因此和原生组件的输出存在行为差异。
  • 提前手动给查询值做编码会触发双重编码:因为queryItems属性内部会对传入的参数值再走一次系统默认转义流程,把已经生成的%转成%25,最终会出现%2540这类后端无法正确解析的字符串。

正确实现方式

核心思路是绕过系统的宽松转义流程,通过percentEncodedQueryItems属性传入已经按规则完成编码的参数,完全避免二次转义:

  1. 自定义转义规则的字符集:在系统提供的CharacterSet.urlQueryAllowed基础上,把需要强制转义的字符(比如@)从允许保留的集合中移除,此时编码过程就会自动把这类字符转成对应的百分号格式。
  2. 对每个查询参数的name、value,按照自定义的字符集规则做一次百分号编码。
  3. 将编码后的参数数组赋值给percentEncodedQueryItems,该属性不会对传入的内容做任何二次修改,只会按照标准格式用&、=拼接查询串。

示例代码:

import UIKit

func createUrl() {
    // 自定义转义用的字符集:从默认查询允许集合里移除@,强制对@做转义
    var forcedEscapeSet = CharacterSet.urlQueryAllowed
    forcedEscapeSet.remove(charactersIn: "@")

    var components = URLComponents()
    components.scheme = "https"
    components.host = "services-test.abc.pippo.com"
    components.path = "/first/second/third"

    let rawItems: [URLQueryItem] = [
        URLQueryItem(name: "amznToken", value: "asfdsfadfasads"),
        URLQueryItem(name: "UID", value: "sdsadasdasdasd"),
        URLQueryItem(name: "login_ID", value: "pippo.pluto@gmail.com"),
        URLQueryItem(name: "ssoEnabled", value: "true"),
        URLQueryItem(name: "country", value: "IT")
    ]

    // 手动完成参数编码后,赋值给percentEncodedQueryItems避免二次转义
    components.percentEncodedQueryItems = rawItems.map { item in
        let encodedName = item.name.addingPercentEncoding(withAllowedCharacters: forcedEscapeSet) ?? item.name
        let encodedValue = item.value?.addingPercentEncoding(withAllowedCharacters: forcedEscapeSet) ?? ""
        return URLQueryItem(name: encodedName, value: encodedValue)
    }

    if let url = components.url {
        print(url.absoluteString)
        // 输出结果:https://services-test.abc.pippo.com/first/second/third?amznToken=asfdsfadfasads&UID=sdsadasdasdasd&login_ID=pippo.pluto%40gmail.com&ssoEnabled=true&country=IT
    }
}

createUrl()

避坑提示

  • 不要在给queryItems赋值前对字符串做任何编码操作,必然触发双重编码问题。
  • 使用percentEncodedQueryItems时,必须保证传入的参数值已经完成所有规则要求的转义,该属性不会帮你处理未转义的特殊字符(比如未转义的&、=会直接破坏查询串结构)。
  • 不要用简单字符串替换的方式把@换成%40,遇到参数本身包含百分号的场景会出现逻辑错误,优先使用系统内置的字符集编码方法。

内容的提问来源于stack exchange,提问作者AR89

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 05:45:04