ios - 如何阻止 Alamofire 对 URL 参数进行编码

标签 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" instead "+"

但是,我需要留下来

"+"

如何使用 Alamofire 避免这种编码?

最佳答案

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

我们需要为此使用自定义编码器。 Alamofire 支持任何实现 ParameterEncoding 协议(protocol)而不是 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())

关于ios - 如何阻止 Alamofire 对 URL 参数进行编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42010219/

相关文章:

ios - 从后台任务启动 iOS 7 中的位置管理器

ios - 使用 SKReferenceNode 引用的 SpriteKit 场景未加载自定义类

ios - RefreshControl 释放时不流畅

ios - 如何使用 Alamofire swift 3 从这个 JSON 中获取值

ios - 将 "StringValue"从一个 View Controller 发送到多个 View Controller 的可能方法?

ios - 无法使用 geoPointForCurrentLocationInBackground 检索地理点

ios - 在 Swift 上,如何在使用 Facebook 登录并使用 FBSDK 解析时检索名称和其他数据

ios - 如何在用户点击 Ui 按钮时将相关数据加载到表中?

swift - 如何更改 UISplitViewController 中的后退按钮?

iOS Alamofire 超时且无网络连接