Как правило, @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())
https://github.com/Alamofire/Alamofire/pull/167/commits/570ed7e8fee36106c93a3251fbb1a97d818e7f09 – Sahil
Нет, вы хотите, чтобы '+' был закодирован как '% 2B'. В противном случае сервер будет обрабатывать '+' как кодировку символа пробела. – rmaddy
Спасибо, ребята, я решил проблему. Вы очень помогли мне –