[Alamofire 소스 해석] 09 - Parameter Encoding
URLEncoding
, JSONEncoding
, PropertyListEncoding
.1. 보조 유형
// , rawValue
public enum HTTPMethod: String {
case options = "OPTIONS"
case get = "GET"
case head = "HEAD"
case post = "POST"
case put = "PUT"
case patch = "PATCH"
case delete = "DELETE"
case trace = "TRACE"
case connect = "CONNECT"
}
// Dictionary
public typealias Parameters = [String: Any]
2.
ParameterEncoding
프로토콜요청에 매개 변수를 어떻게 인코딩하는지 규정했다.
public protocol ParameterEncoding {
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
}
3.
URLEncoding
매개변수를 URL에 직접 인코딩합니다.
1).
Destination
요청에 매개 변수를 인코딩하는 세 가지 방식을 열거했다.
// methodDependent: ,`GET`, `HEAD` `DELETE` url , HTTP body
// queryString: url
// httpBody: HTTP body
public enum Destination {
case methodDependent, queryString, httpBody
}
2). 속성 및 초기화
// methodDependent URLEncoding
public static var `default`: URLEncoding { return URLEncoding() }
// methodDependent URLEncoding , default
public static var methodDependent: URLEncoding { return URLEncoding() }
// queryString URLEncoding
public static var queryString: URLEncoding { return URLEncoding(destination: .queryString) }
// httpBody URLEncoding
public static var httpBody: URLEncoding { return URLEncoding(destination: .httpBody) }
public let destination: Destination
public init(destination: Destination = .methodDependent) {
self.destination = destination
}
3). 부호화
// ParameterEncoding
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
// ,
guard let parameters = parameters else { return urlRequest }
// URL
if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) {
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
}
} else { // HTTP body
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
}
return urlRequest
}
// key value,
public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {
var components: [(String, String)] = []
if let dictionary = value as? [String: Any] { // value
for (nestedKey, value) in dictionary {
// key value
components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
}
} else if let array = value as? [Any] { // value
for value in array {
// key value
components += queryComponents(fromKey: "\(key)[]", value: value)
}
} else if let value = value as? NSNumber { // value NSNumber
if value.isBool {
// NSNumber Bool , 1 0
components.append((escape(key), escape((value.boolValue ? "1" : "0"))))
} else {
components.append((escape(key), escape("\(value)")))
}
} else if let bool = value as? Bool { // value Bool , 1 0
components.append((escape(key), escape((bool ? "1" : "0"))))
} else {
components.append((escape(key), escape("\(value)")))
}
return components
}
// 。
// :
// - General Delimiters: ":", "#", "[", "]", "@"
// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
public func escape(_ string: String) -> String {
let generalDelimitersToEncode = ":#[]@"
let subDelimitersToEncode = "!$&'()*+,;="
var allowedCharacterSet = CharacterSet.urlQueryAllowed
allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
var escaped = ""
//==========================================================================================================
//
// iOS 8.1 8.2 , crash,
// ( bug , issue:https://github.com/Alamofire/Alamofire/issues/206)
//
//==========================================================================================================
if #available(iOS 8.3, *) {
escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
} else {
let batchSize = 50
var index = string.startIndex
while index != string.endIndex {
let startIndex = index
let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex
let range = startIndex.. String {
var components: [(String, String)] = []
// ` Bool {
switch destination {
case .queryString:
return true
case .httpBody:
return false
default:
break
}
switch method {
case .get, .head, .delete:
return true
default:
return false
}
}
4.
JSONEncoding
요청체에 SJON 형식으로 매개변수를 인코딩합니다.
1). 속성 및 초기화
// JSONEncoding
public static var `default`: JSONEncoding { return JSONEncoding() }
// JSONEncoding
public static var prettyPrinted: JSONEncoding { return JSONEncoding(options: .prettyPrinted) }
public let options: JSONSerialization.WritingOptions
public init(options: JSONSerialization.WritingOptions = []) {
self.options = options
}
2). 부호화
//
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
// ,
guard let parameters = parameters else { return urlRequest }
do {
// JSON
let data = try JSONSerialization.data(withJSONObject: parameters, options: options)
// Content-Type
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = data
} catch {
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}
return urlRequest
}
// ,
public func encode(_ urlRequest: URLRequestConvertible, withJSONObject jsonObject: Any? = nil) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard let jsonObject = jsonObject else { return urlRequest }
do {
// JSON
let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options)
// Content-Type
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = data
} catch {
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}
return urlRequest
}
5.
PropertyListEncoding
매개변수를 PropertyList 형식으로 요청체에 인코딩합니다.
1). 속성 및 초기화
// PropertyListEncoding , xml
public static var `default`: PropertyListEncoding { return PropertyListEncoding() }
// xm PropertyListEncoding
public static var xml: PropertyListEncoding { return PropertyListEncoding(format: .xml) }
// PropertyListEncoding
public static var binary: PropertyListEncoding { return PropertyListEncoding(format: .binary) }
public let format: PropertyListSerialization.PropertyListFormat
public let options: PropertyListSerialization.WriteOptions
public init(
format: PropertyListSerialization.PropertyListFormat = .xml,
options: PropertyListSerialization.WriteOptions = 0)
{
self.format = format
self.options = options
}
2). 부호화
// ParameterEncoding
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard let parameters = parameters else { return urlRequest }
do {
// PropertyList
let data = try PropertyListSerialization.data(
fromPropertyList: parameters,
format: format,
options: options
)
// Content-Type
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("application/x-plist", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = data
} catch {
throw AFError.parameterEncodingFailed(reason: .propertyListEncodingFailed(error: error))
}
return urlRequest
}
어떤 문제가 있으면 여러분의 메모를 환영합니다!
제가 관리하는 Swift 개발 그룹에 가입하신 것을 환영합니다.
536353151
이 그룹에서는 Swift와 관련된 내용만 토론합니다.오리지널 문장, 전재는 출처를 밝혀 주십시오.감사합니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.