如何阻止Alamofire编码URL参数

时间:2017-02-02 18:58:54

标签: ios swift alamofire

我有这样的网址

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避免编码?

2 个答案:

答案 0 :(得分: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())

答案 1 :(得分:1)

虽然这个问题已经得到了回答,但对于那些刚接触并且可能是第一次使用Alamofire并面临问题的人来说。

下面,

baseUrl =&#34; https://www.baseUrl.com/&#34;,

path =&#34; user / anything / status?current = Single&#34; 这就是我所做的(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%3F 当前=单

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

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

希望它有所帮助。