欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Swift中的HTTP請(qǐng)求體Request Bodies使用示例詳解

 更新時(shí)間:2023年02月03日 15:20:54   作者:莊周曉夢  
這篇文章主要為大家介紹了Swift中的HTTP請(qǐng)求體Request Bodies使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

在進(jìn)行HTTPRequest請(qǐng)求發(fā)送前,我們稍稍改進(jìn)一下我們的結(jié)構(gòu)體,最后,我們將會(huì)以下面的信息輸出:

public struct HTTPRequest {
    private var urlComponents = URLComponents()
    public var method: HTTPMethod = .get
    public var headers: [String: String] = [:]
    public var body: Data?
}

在本節(jié)中,我們將著重討論一下body屬性,并對(duì)其進(jìn)行改造。

通用化body

在HTTP簡介那一節(jié),我們了解到,一個(gè)請(qǐng)求體是原始二進(jìn)制數(shù)據(jù),但是,在與 Web API 通信時(shí),這些數(shù)據(jù)有多種標(biāo)準(zhǔn)格式,例如 JSON 和表單提交。

我們可以將其概括為一種“給我們數(shù)據(jù)的東西”的形式,而不是要求此代碼的客戶手動(dòng)構(gòu)造其提交數(shù)據(jù)的二進(jìn)制表示。

由于我們不打算對(duì)用于構(gòu)造數(shù)據(jù)的算法施加任何限制,因此通過協(xié)議而不是具體類型來定義此功能是有意義的:

public protocol HTTPBody { }

接下來,我們需要一種方法從其中一個(gè)值中獲取Data,并在出現(xiàn)問題時(shí)選擇性地報(bào)告錯(cuò)誤:

public protocol HTTPBody { 
    func encode() throws -> Data 
}

我們可以在這一點(diǎn)上停下來,但還有另外兩條信息值得擁有:

public protocol HTTPBody { 
    var isEmpty: Bool { get }
    var additionalHeaders: [String: String] { get } 
    func encode() throws -> Data 
}

如果我們能快速知道一個(gè)body是空的,那么我們就可以省去嘗試檢索任何編碼數(shù)據(jù)和處理錯(cuò)誤或空數(shù)據(jù)值的麻煩。

此外,某些類型的正文與請(qǐng)求中的header結(jié)合使用。 例如,當(dāng)我們將值編碼為 JSON 時(shí),我們希望有一種方法可以自動(dòng)指定 Content-Type: application/json 的header,而無需在請(qǐng)求中手動(dòng)指定它。 為此,我們將允許這些類型聲明額外的header,這些標(biāo)頭將作為最終請(qǐng)求的一部分結(jié)束。 為了進(jìn)一步簡化采用,我們可以為這些提供默認(rèn)實(shí)現(xiàn):

extension HTTPBody {
    public var isEmpty: Bool { return false }
    public var additionalHeaders: [String: String] { return [:] }
}

最后,我們可以將我們的類型更新到這個(gè)新的協(xié)議中

public struct HTTPRequest {
    private var urlComponents = URLComponents()
    public var method: HTTPMethod = .get
    public var headers: [String: String] = [:]
    public var body: HTTPBody?
}

空請(qǐng)求體 EmptyBody

最簡單的HTTPBody是”無體“。有了這個(gè)協(xié)議,定義一個(gè)空請(qǐng)求體也是很方便的。

public struct EmptyBody: HTTPBody {
    public let isEmpty = true
    public init() { }
    public func encode() throws -> Data { Data() }
}

我們甚至可以將其設(shè)置為默認(rèn)的主體值,從而完全消除對(duì)該屬性的可選性的需要:

public struct HTTPRequest {
    private var urlComponents = URLComponents()
    public var method: HTTPMethod = .get
    public var headers: [String: String] = [:]
    public var body: HTTPBody = EmptyBody()
}

數(shù)據(jù)體 DataBody

下一個(gè)明顯要實(shí)現(xiàn)的主體類型是返回給定的任何Data值的主體。 這將用于我們不一定有 HTTPBody 實(shí)現(xiàn)但也許我們已經(jīng)有Data值本身要發(fā)送的情況。

具體實(shí)現(xiàn)如下:

public struct DataBody: HTTPBody {    
    private let data: Data
    public var isEmpty: Bool { data.isEmpty }
    public var additionalHeaders: [String: String]
    public init(_ data: Data, additionalHeaders: [String: String] = [:]) {
        self.data = data
        self.additionalHeaders = additionalHeaders
    }
    public func encode() throws -> Data { data }    
}

有了這個(gè),我們可以很輕松的將一個(gè)Data值封裝進(jìn)HTTPBody里:

let otherData: Data = ...
var request = HTTPRequest()
request.body = DataBody(otherData)

JSON體 JSONBody

在發(fā)送網(wǎng)絡(luò)請(qǐng)求時(shí),將值編碼為 JSON 是一項(xiàng)非常常見的任務(wù)。 制作一個(gè) HTTPBody 來為我們處理這個(gè)現(xiàn)在很容易:

public struct JSONBody: HTTPBody {
    public let isEmpty: Bool = false
    public var additionalHeaders = [
        "Content-Type": "application/json; charset=utf-8"
    ]
    private let encode: () throws -> Data
    public init<T: Encodable>(_ value: T, encoder: JSONEncoder = JSONEncoder()) {
        self.encode = { try encoder.encode(value) }
    }
    public func encode() throws -> Data { return try encode() }
}

首先,我們假設(shè)我們得到的任何值都會(huì)至少產(chǎn)生一些結(jié)果,因?yàn)榧词故强兆址矔?huì)編碼為非空 JSON 值。 因此,isEmpty = false。

接下來,大多數(shù)服務(wù)器在接收 JSON 正文時(shí)需要 application/jsonContent-Type,因此我們假設(shè)這是常見情況,并在 additionalHeaders 中默認(rèn)該值。 但是,我們會(huì)將該屬性保留為 var,以防萬一出現(xiàn)客戶不希望這樣的情況。

對(duì)于編碼,我們需要接受一些通用值(要編碼的東西),但最好不要讓整個(gè)結(jié)構(gòu)對(duì)編碼類型通用。 我們可以通過將類型的泛型參數(shù)限制為初始化器來避免類型的泛型參數(shù),然后在閉包中捕獲泛型值。

我們還需要一種方法來提供自定義 JSONEncoder,以便客戶有機(jī)會(huì)擺弄諸如 .keyEncodingStrategy 之類的東西。 但是,我們將提供一個(gè)默認(rèn)編碼器來簡化使用。

最后,encode() 方法本身只是調(diào)用我們創(chuàng)建的閉包,它捕獲通用值并通過 JSONEncoder 執(zhí)行它。

其中一個(gè)的使用方法如下:

struct PagingParameters: Encodable {
    let page: Int
    let number: Int
}
let parameters = PagingParameters(page: 0, number: 10)
var request = HTTPRequest()
request.body = JSONBody(parameters)

這樣,正文將自動(dòng)編碼為 {"page":0,"number":10},我們的最終請(qǐng)求將具有正確的 Content-Type 標(biāo)頭。

表單 FormBody

我們將在本文中看到的最后一種主體是表示基本表單提交的body。 當(dāng)我們專門討論多部分表單上傳時(shí),我們將保存文件上傳以備將來使用。

表單提交正文最終為粗略的 URL 編碼鍵值對(duì),例如 name=Arthur&age=42。

我們將從與我們的 HTTPBody 實(shí)現(xiàn)相同的基本結(jié)構(gòu)開始:

public struct FormBody: HTTPBody {
    public var isEmpty: Bool { values.isEmpty }
    public let additionalHeaders = [
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8"
    ]
    private let values: [URLQueryItem]
    public init(_ values: [URLQueryItem]) {
        self.values = values
    }
    public init(_ values: [String: String]) {
        let queryItems = values.map { URLQueryItem(name: $0.key, value: $0.value) }
        self.init(queryItems)
    }
    public func encode() throws -> Data {
        let pieces = values.map { /* TODO */ }
        let bodyString = pieces.joined(separator: "&")
        return Data(bodyString.utf8)
    }
}

和以前一樣,我們有一個(gè)自定義的 Content-Type 標(biāo)頭來應(yīng)用于請(qǐng)求。 我們還公開了幾個(gè)初始化器,以便客戶端可以以對(duì)他們有意義的方式描述這些值。 我們還刪除了大部分 encode() 方法,省略了 URLQueryItem 值的實(shí)際編碼。

不幸的是,對(duì)名稱和值進(jìn)行編碼有點(diǎn)模棱兩可。 如果你仔細(xì)閱讀關(guān)于表單提交的古老規(guī)范,你會(huì)看到提到“換行規(guī)范化”和將空格編碼為 + 的內(nèi)容。 我們可以努力挖掘并找出這些東西的含義,但在實(shí)踐中,Web 服務(wù)器往往可以很好地處理任何百分比編碼的內(nèi)容,甚至是空格。 我們將走捷徑并假設(shè)這是真的。 我們還將全面假設(shè)字母數(shù)字字符在名稱和值中是可以的,并且其他所有內(nèi)容都應(yīng)該被編碼:

private func urlEncode(_ string: String) -> String {
    let allowedCharacters = CharacterSet.alphanumerics
    return string.addingPercentEncoding(withAllowedCharacters: allowedCharacters) ?? ""
}

使用 = 字符組合名稱和值:

private func urlEncode(_ queryItem: URLQueryItem) -> String {
    let name = urlEncode(queryItem.name)
    let value = urlEncode(queryItem.value ?? "")
    return "(name)=(value)"
}

有了這個(gè),我們可以解決 /* TODO */ 評(píng)論:

public struct FormBody: HTTPBody {
    public var isEmpty: Bool { values.isEmpty }
    public let additionalHeaders = [
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8"
    ]
    private let values: [URLQueryItem]
    public init(_ values: [URLQueryItem]) {
        self.values = values
    }
    public init(_ values: [String: String]) {
        let queryItems = values.map { URLQueryItem(name: $0.key, value: $0.value) }
        self.init(queryItems)
    }
    public func encode() throws -> Data {
        let pieces = values.map(self.urlEncode)
        let bodyString = pieces.joined(separator: "&")
        return Data(bodyString.utf8)
    }
    private func urlEncode(_ queryItem: URLQueryItem) -> String {
        let name = urlEncode(queryItem.name)
        let value = urlEncode(queryItem.value ?? "")
        return "(name)=(value)"
    }
    private func urlEncode(_ string: String) -> String {
        let allowedCharacters = CharacterSet.alphanumerics
        return string.addingPercentEncoding(withAllowedCharacters: allowedCharacters) ?? ""
    }
}

和以前一樣,使用它變得很簡單:

var request = HTTPRequest()
request.body = FormBody(["greeting": "Hello, ", "target": "??"])
// the body is encoded as:
// greeting=Hello%2C%20&target=%F0%9F%8C%8E

其他Body Other Bodies

您可以在 HTTP 請(qǐng)求中發(fā)送的正文格式多種多樣。 我已經(jīng)提到過,我們將來會(huì)更仔細(xì)地研究多部分請(qǐng)求,但是這種 HTTPBody 方法幾乎適用于您會(huì)遇到的每一種請(qǐng)求體。

在下一篇文章中,我們將描述 HTTP 請(qǐng)求加載抽象層并使用 URLSession 實(shí)現(xiàn)它。

以上就是Swift中的HTTP請(qǐng)求體Request Bodies使用示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Swift HTTP請(qǐng)求體Request Bodies的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解iOS集成融云SDK即時(shí)通訊整理

    詳解iOS集成融云SDK即時(shí)通訊整理

    這篇文章主要介紹了詳解iOS集成融云SDK即時(shí)通訊整理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • iOS路由(MGJRouter)的實(shí)現(xiàn)

    iOS路由(MGJRouter)的實(shí)現(xiàn)

    這篇文章主要介紹了iOS路由(MGJRouter)的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • iOS開發(fā)之自定義圖片拉伸功能

    iOS開發(fā)之自定義圖片拉伸功能

    這篇文章主要介紹了iOS開發(fā)之自定義圖片拉伸功能,需要的朋友可以參考下
    2017-06-06
  • iOS中利用CAEmitterLayer實(shí)現(xiàn)粒子動(dòng)畫詳解

    iOS中利用CAEmitterLayer實(shí)現(xiàn)粒子動(dòng)畫詳解

    粒子效果應(yīng)該對(duì)現(xiàn)在很多人來說并不陌生,我們之前也分享了一些相關(guān)文章,下面這篇文章主要給大家介紹了關(guān)于iOS中利用CAEmitterLayer實(shí)現(xiàn)粒子動(dòng)畫的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友們下面來一起看看吧。
    2017-06-06
  • iOS開發(fā)中AVPlayer的簡單應(yīng)用

    iOS開發(fā)中AVPlayer的簡單應(yīng)用

    這篇文章主要介紹了iOS開發(fā)中AVPlayer的簡單應(yīng)用,文中給出了簡單的介紹和示例代碼,相信對(duì)大家學(xué)習(xí)AVPlayer的應(yīng)用具有一定的參考價(jià)值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)。
    2017-02-02
  • 檢測iOS設(shè)備是否越獄的方法

    檢測iOS設(shè)備是否越獄的方法

    這篇文章主要介紹了檢測iOS設(shè)備是否越獄的方法,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下
    2015-10-10
  • UIWebView控件中字體大小和字體樣式的修改

    UIWebView控件中字體大小和字體樣式的修改

    本文主要介紹了UIWebView控件中字體大小和字體樣式的修改,具有很好的參考價(jià)值。下面跟著小編一起來看下吧
    2017-03-03
  • 支付寶支付開發(fā)IOS圖文教程案例

    支付寶支付開發(fā)IOS圖文教程案例

    這篇文章主要介紹了支付寶支付開發(fā)IOS案例的相關(guān)資料,需要的朋友可以參考下
    2016-04-04
  • iOS 獲取設(shè)備唯一標(biāo)示符的方法詳解

    iOS 獲取設(shè)備唯一標(biāo)示符的方法詳解

    本篇文章主要介紹了iOS 獲取設(shè)備唯一標(biāo)示符的方法詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • iOS獲取驗(yàn)證碼倒計(jì)時(shí)效果

    iOS獲取驗(yàn)證碼倒計(jì)時(shí)效果

    這篇文章主要為大家詳細(xì)介紹了iOS獲取驗(yàn)證碼倒計(jì)時(shí)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11

最新評(píng)論