如何将空格与+转为URL编码?解决URLQueryItem编码失效问题
解决URLQueryItem无法正确编码+和空格的问题
默认的URLQueryItem会按照RFC 3986规则处理编码:空格会被转为+,而+字符会直接保留不编码,这和你需要的「空格编码为%20、+编码为%2B」需求不符。可以通过以下两种方式解决:
方案一:手动构建编码后的查询字符串
自定义编码逻辑,对每个参数值做针对性处理,再拼接成查询字符串:
// 自定义参数编码函数 func encodeQueryValue(_ value: String) -> String? { // 先替换空格为%20 let spaceEncoded = value.replacingOccurrences(of: " ", with: "%20") // 替换+为%2B let plusEncoded = spaceEncoded.replacingOccurrences(of: "+", with: "%2B") // 处理其他需要编码的特殊字符(排除+,避免被再次保留) let allowedChars = CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "+")) return plusEncoded.addingPercentEncoding(withAllowedCharacters: allowedChars) } // 构建完整URL let baseURL = URL(string: "https://your-server.com/api")! var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: true)! // 定义参数 let parameters = [ "param1": "text with spaces", "param2": "text+with+pluses" ] // 拼接编码后的查询项 let encodedQuery = parameters.compactMap { key, value -> String? in guard let encodedVal = encodeQueryValue(value) else { return nil } let encodedKey = key.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? key return "\(encodedKey)=\(encodedVal)" }.joined(separator: "&") components.percentEncodedQuery = encodedQuery // 最终可用的URL if let finalURL = components.url { print(finalURL.absoluteString) // 输出示例:https://your-server.com/api?param1=text%20with%20spaces¶m2=text%2Bwith%2Bpluses }
方案二:扩展URLComponents实现自动编码
通过扩展URLComponents,自定义customQueryItems属性,让它自动应用你的编码规则:
extension URLComponents { var customQueryItems: [URLQueryItem]? { get { queryItems } set { guard let items = newValue else { percentEncodedQuery = nil return } percentEncodedQuery = items.compactMap { item -> String? in guard let encodedVal = self.encodeQueryValue(item.value ?? "") else { return nil } let encodedKey = item.name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? item.name return "\(encodedKey)=\(encodedVal)" }.joined(separator: "&") } } private func encodeQueryValue(_ value: String) -> String? { let spaceEncoded = value.replacingOccurrences(of: " ", with: "%20") let plusEncoded = spaceEncoded.replacingOccurrences(of: "+", with: "%2B") let allowedChars = CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "+")) return plusEncoded.addingPercentEncoding(withAllowedCharacters: allowedChars) } }
使用时直接设置customQueryItems即可:
let baseURL = URL(string: "https://your-server.com/api")! var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: true)! components.customQueryItems = [ URLQueryItem(name: "param1", value: "text with spaces"), URLQueryItem(name: "param2", value: "text+with+pluses") ] if let finalURL = components.url { // 使用finalURL发起请求 }
两种方案的核心都是先手动替换空格和+为目标编码,再处理其他特殊字符,确保最终的URL参数完全符合服务器的解析要求。
内容的提问来源于stack exchange,提问作者noW0rds
相关产品推荐
相关产品推荐

