I have an url like that
https://www.mysite/v1/search?N=4249847587+1798040122
I use Alamofire like that
Almofire.request(.GET, "https://www.mysite/v1/search", parameters: ["N","4249847587+1798040122"], encoding: .URL)
Logging the request, I receive
https://www.mysite/v1/search?N=4249847587%2B1798040122
i.e
"%2B" instead "+"
But, I need to remain with
"+"
How can I avoid that encoding using Alamofire?
Generally @rmaddy is right in his comment. But we can turn this encoding off as some fun exercise.
We will need to use custom encoder for this. Alamofire supports any custom encoder which implements ParameterEncoding
protocol instead of encoding: .URL
.
So ve can use a bit of copy&pasted code from original Alamofire codebase and create custom encoder
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) }
}
I don't have idea why it can be useful. But custom encoding can be added easily. Now you just can use Alamofire request with our new encoder
Alamofire.request("http://www.mysite/v1/search", method: .get, parameters: ["N": "4249847587+1798040122"], encoding: NOURLEncoding())
Though the question has been answered just for those who are New to swift and probably using Alamofire for the first time and facing issues.
Here,
baseUrl = "https://www.baseUrl.com/",
path = "user/anything/status?current=Single" This is what I did (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!)
or
let wholeURL = baseUrl.appending(path)
let urlwithPercent = wholeURL.addingPercentEncoding( withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
var URLRequest = Foundation.URLRequest(url: URL(string: urlwithPercent!)!)
Now the Story is :
My url was getting Converted to something like this :
https://www.baseUrl.com/user/anything/status%3Fcurrent=Single
the response was coming as 403. after searching online for around 4 hours I couldn't find a simple and small fix. Then by removing percent encoding solved the problem. Also, this isn't the right approach as said in the comments by @rmaddy.
And this applies to all the special character encoding irregardless of whether it is a question mark, exclamation mark or anything..
Hope it helps someone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With