如何阻止 Alamofire 编码 URL 参数

Posted

技术标签:

【中文标题】如何阻止 Alamofire 编码 URL 参数【英文标题】:How to block Alamofire from encoding of URL parameters 【发布时间】:2017-02-02 18:58:54 【问题描述】:

我有一个这样的网址

https://www.mysite/v1/search?N=4249847587+1798040122

我就是这样用 Alamofire 的

Almofire.request(.GET, "https://www.mysite/v1/search", parameters: ["N","4249847587+1798040122"], encoding: .URL)

记录请求,我收到

https://www.mysite/v1/search?N=4249847587%2B1798040122

“%2B”而不是“+”

但是,我需要留下来

“+”

如何避免使用 Alamofire 进行编码?

【问题讨论】:

github.com/Alamofire/Alamofire/pull/167/commits/… 不,您希望将+ 编码为%2B。否则服务器会将+ 视为空格字符的编码。 谢谢各位,我已经解决了这个问题。你帮了我很多 【参考方案1】:

通常@rmaddy 在他的评论中是正确的。但是我们可以关闭这种编码作为一些有趣的练习。

我们需要为此使用自定义编码器。 Alamofire 支持任何实现ParameterEncoding 协议而不是encoding: .URL 的自定义编码器。

所以我们可以使用一些来自原始 Alamofire 代码库的复制和粘贴代码并创建自定义编码器

public struct NOURLEncoding: ParameterEncoding 

    //protocol implementation
    public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest 
        var urlRequest = try urlRequest.asURLRequest()

        guard let parameters = parameters else  return urlRequest 

        if HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET") != nil 
            guard let url = urlRequest.url else 
                throw AFError.parameterEncodingFailed(reason: .missingURL)
            

            if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty 
                let percentEncodedQuery = (urlComponents.percentEncodedQuery.map  $0 + "&"  ?? "") + query(parameters)
                urlComponents.percentEncodedQuery = percentEncodedQuery
                urlRequest.url = urlComponents.url
            
        

        return urlRequest
    

    //append query parameters 
    private func query(_ parameters: [String: Any]) -> String 
        var components: [(String, String)] = []

        for key in parameters.keys.sorted(by: <) 
            let value = parameters[key]!
            components += queryComponents(fromKey: key, value: value)
        

        return components.map  "\($0)=\($1)" .joined(separator: "&")
    

    //Alamofire logic for query components handling
    public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] 
        var components: [(String, String)] = []

        if let dictionary = value as? [String: Any] 
            for (nestedKey, value) in dictionary 
                components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
            
         else if let array = value as? [Any] 
            for value in array 
                components += queryComponents(fromKey: "\(key)[]", value: value)
            
         else if let value = value as? NSNumber 
            if value.isBool 
                components.append((escape(key), escape((value.boolValue ? "1" : "0"))))
             else 
                components.append((escape(key), escape("\(value)")))
            
         else if let bool = value as? Bool 
            components.append((escape(key), escape((bool ? "1" : "0"))))
         else 
            components.append((escape(key), escape("\(value)")))
        

        return components
    

    //escaping function where we can select symbols which we want to escape 
    //(I just removed + for example)
    public func escape(_ string: String) -> String 
        let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
        let subDelimitersToEncode = "!$&'()*,;="

        var allowedCharacterSet = CharacterSet.urlQueryAllowed
        allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")

        var escaped = ""

        escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string

        return escaped
    

 

extension NSNumber 
    fileprivate var isBool: Bool  return CFBooleanGetTypeID() == CFGetTypeID(self) 

我不知道它为什么有用。但是可以轻松添加自定义编码。现在您可以使用我们的新编码器使用 Alamofire 请求

Alamofire.request("http://www.mysite/v1/search", method: .get, parameters: ["N": "4249847587+1798040122"], encoding: NOURLEncoding())

【讨论】:

【参考方案2】:

虽然这个问题只针对那些不熟悉 swift 并且可能是第一次使用 Alamofire 并面临问题的人。

这里,

baseUrl = "https://www.baseUrl.com/",

path = "用户/任何东西/状态?当前=单身" 这就是我所做的(Swift 3.0,Alamofire v4.4)

let completeUrl = baseUrl.appending(path)
let urlWithoutPercent = completeUrl.removingPercentEncoding
let finalUrl = URL(string: urlWithoutPercent!)
var URLRequest = Foundation.URLRequest(url: finalUrl!)

 let wholeURL = baseUrl.appending(path)
 let urlwithPercent = wholeURL.addingPercentEncoding( withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
 var URLRequest = Foundation.URLRequest(url: URL(string: urlwithPercent!)!)

现在的故事是:

我的网址被转换成这样的:

https://www.baseUrl.com/user/anything/status%3Fcurrent=Single

响应是 403。 在网上搜索了大约 4 个小时后,我找不到一个简单而小的修复程序。然后通过删除百分比编码解决了这个问题。 此外,这不是 @rmaddy 在 cmets 中所说的正确方法。

这适用于所有特殊字符编码,无论是问号、感叹号还是其他任何东西..

希望对某人有所帮助。

【讨论】:

免责声明:您的其他 api 调用可能不会给出所需的响应......总之它们可能会失败......这个技巧只适用于具有特殊字符参数的 url。

以上是关于如何阻止 Alamofire 编码 URL 参数的主要内容,如果未能解决你的问题,请参考以下文章

使用 SwiftyJSON 对 Alamofire GET 参数进行 URL 编码

Alamofire .POST 编码 (.URL)

URL编码参数中的布尔值在Swift3中使用Alamofire编码为0和1

在 Alamofire 中使用之前对 URL 进行编码

ios alamofire4.x网络框架url 中文问题

AlamoFire 4.X 中的 URL 编码