Swift 上傳文件

pic.jpg

前言

最近在使用Vapor遇到很多的問(wèn)題掸屡,坑也填了不少解阅,下面就來(lái)說(shuō)說(shuō)由這個(gè)坑引發(fā)一系列的問(wèn)題。

需求

在應(yīng)用里闸氮,需要使用保存用戶(hù)的上傳頭像剪况,那么問(wèn)題來(lái)了,如果發(fā)布到heroku上蒲跨,空間是有限的译断,然而用戶(hù)量是不可估計(jì)的,所以在對(duì)比了國(guó)內(nèi)幾家的OSS后或悲,選擇了七牛對(duì)象存儲(chǔ)做為圖片的存儲(chǔ)空間孙咪,上傳的圖片的庫(kù)已經(jīng)找好,用的是Alamofire巡语。

問(wèn)題

在使用Alamofire時(shí)翎蹈,發(fā)現(xiàn)一個(gè)了問(wèn)題,我們都知道Alamofire這個(gè)庫(kù)使用得最多的iOS開(kāi)發(fā)男公,而用Alamofire做iOS的網(wǎng)絡(luò)請(qǐng)求荤堪,它的內(nèi)部返回的結(jié)果都是在主線(xiàn)程下執(zhí)行的,這樣做的確方便了iOS開(kāi)發(fā)的枢赔,但是在Vapor里主線(xiàn)程是會(huì)被攔截而不被觸發(fā)的澄阳,所以在使用Alamofire上傳圖片時(shí),結(jié)果是不會(huì)返回的踏拜。

思考

第一想到的是Alamofire是否有相關(guān)的API可以使用碎赢,但是遺憾的是,只有在返回結(jié)果后速梗,對(duì)結(jié)果進(jìn)行處理時(shí)才有肮塞,所以這個(gè)方案fail。第三方的實(shí)現(xiàn)不了姻锁,那只能自己實(shí)現(xiàn)這個(gè)功能了枕赵。

正文

在查看了七牛的文檔后屋摔,看到七牛上傳api是表單上傳烁设,先來(lái)看個(gè)示例。

Content-Type:   multipart/form-data; boundary=分隔線(xiàn)

--分隔線(xiàn)
Content-Disposition:       form-data; name="token"
<uploadToken>
--分隔線(xiàn)
Content-Disposition:       form-data; name="key"
<key>
--分隔線(xiàn)
Content-Disposition:       form-data; name="file"; filename="<fileName>"
Content-Type:              application/octet-stream
Content-Transfer-Encoding: binary
<fileBinaryData>
--分隔線(xiàn)--

上面的示例中钓试,需要傳入的參數(shù)有三個(gè),token,key,file。在七牛中副瀑,token是要自己生成的弓熏,這里就不多說(shuō)明了,想了解的話(huà)可以私信博主糠睡。上傳的boundary=分隔線(xiàn)是給后臺(tái)解析時(shí)用的挽鞠,博主看到Alamofire里的是以這個(gè)String(format: "Alamofire.boundary.%08x%08x", arc4random(), arc4random())為分隔線(xiàn)的,博主的分隔線(xiàn)只是把Alamofire給去掉。

最后生成像下面這樣:

Content-Type:   multipart/form-data; boundary=boundary.73e735e3732b6c0e

知道怎么生成就開(kāi)始構(gòu)建了信认。

let url = URL(string:"http://up.qiniu.com")

var request = URLRequest.init(url: url!);
// 請(qǐng)求類(lèi)型
request.httpMethod = "POST";
// 超時(shí)時(shí)間
request.timeoutInterval = 30;

// 設(shè)置分隔線(xiàn)
let boundary = String(format: "boundary.%08x%08x", arc4random(), arc4random())
let contentType = String(format: "multipart/form-data;boundary=%@", boundary)
request.addValue(contentType, forHTTPHeaderField: "Content-Type")

// 創(chuàng)建body
var body = Data();

// 請(qǐng)求參數(shù)
let dict = ["token":token,"key": key]
let keys = dict.keys;

for key in keys {
    body.append(String(format:"--%@\r\n",boundary).data(using: .utf8)!)
    body.append(String(format:"Content-Disposition:form-data;name=\"%@\"\r\n\r\n",key as String).data(using: .utf8)!)
    body.append("\(dict[key]!)\r\n".data(using: .utf8)!)
}
// 數(shù)據(jù)之前要用 --分隔線(xiàn) 來(lái)隔開(kāi) 材义,否則后臺(tái)會(huì)解析失敗
body.append(String(format:"--%@\r\n",boundary).data(using: .utf8)!)

// 文件
let key = "1.jpg"

// 文件主體
let data = UIImagePNGRepresentation(UIImage.init(named: key)!);

let file = "file"
// 傳入最后一個(gè)參數(shù)
body.append(String(format:"Content-Disposition:form-data;name=\"%@\";filename=\"\(key)\"\r\n", file).data(using: .utf8)!)

// 文件類(lèi)型
body.append("Content-Type:image/jpeg\r\n\r\n".data(using: .utf8)!)

// 添加文件主體
body.append(data)

// 使用\r\n來(lái)表示這個(gè)這個(gè)值的結(jié)束符
body.append("\r\n".data(using: .utf8)!)

// --分隔線(xiàn)-- 為整個(gè)表單的結(jié)束符
body.append(String(format:"--%@--\r\n",boundary).data(using: .utf8)!)

// 上傳表單
URLSession.shared.uploadTask(with: request, from: body) { (data, resp, error) in

    do{
        let d = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
        print(d)
    }catch{
        print(error)
    }
}.resume()

上面的代碼在OS上是沒(méi)問(wèn)題的,但是在Linux上就會(huì)報(bào)錯(cuò)(更新于2017.9.6)

fatal error: shared is not yet implemented: file Foundation/NSURLSession/NSURLSession.swift

這是由于使用的URLSession.shared在Linux上還沒(méi)有被實(shí)現(xiàn)嫁赏,這里有說(shuō)道原因其掂。如果想了解還有那些在Linux上缺失的可以點(diǎn)這里。shared不能使用潦蝇,我們就換個(gè)方法款熬。

// 生成body的方法和上面的一樣
request.httpBody = body

// 使用URLSessionConfiguration.default來(lái)生成URLSession
let session = URLSession(
        configuration:URLSessionConfiguration.default, delegate: nil, delegateQueue: nil)

let dataTask = session.dataTask(with: request, completionHandler: {[weak self] (data, response, error) -> Void in
            let tuple = self?.c(data: data, response: response, err: error);
            completion((tuple?.0)!,tuple?.1)
        })
dataTask.resume()

以上就是一個(gè)很全面的一次表單多參數(shù)上傳的示例了,還有不明白的童鞋可以私信博主攘乒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贤牛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子则酝,更是在濱河造成了極大的恐慌殉簸,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沽讹,死亡現(xiàn)場(chǎng)離奇詭異喂链,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)妥泉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)椭微,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人盲链,你說(shuō)我怎么就攤上這事蝇率。” “怎么了刽沾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵本慕,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我侧漓,道長(zhǎng)锅尘,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任布蔗,我火速辦了婚禮藤违,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纵揍。我一直安慰自己顿乒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布泽谨。 她就那樣靜靜地躺著璧榄,像睡著了一般特漩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上骨杂,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天涂身,我揣著相機(jī)與錄音,去河邊找鬼搓蚪。 笑死蛤售,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的陕凹。 我是一名探鬼主播悍抑,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼杜耙!你這毒婦竟也來(lái)了搜骡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤佑女,失蹤者是張志新(化名)和其女友劉穎记靡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體团驱,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摸吠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚎花。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寸痢。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖紊选,靈堂內(nèi)的尸體忽然破棺而出啼止,到底是詐尸還是另有隱情,我是刑警寧澤兵罢,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布献烦,位于F島的核電站,受9級(jí)特大地震影響卖词,放射性物質(zhì)發(fā)生泄漏巩那。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一此蜈、第九天 我趴在偏房一處隱蔽的房頂上張望即横。 院中可真熱鬧,春花似錦舶替、人聲如沸令境。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)舔庶。三九已至,卻和暖如春陈醒,著一層夾襖步出監(jiān)牢的瞬間惕橙,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工钉跷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弥鹦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓爷辙,卻偏偏與公主長(zhǎng)得像彬坏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膝晾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理栓始,服務(wù)發(fā)現(xiàn),斷路器血当,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)幻赚、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,022評(píng)論 4 62
  • 需求 當(dāng) Toolbar 布局放在底層的 Activity 中臊旭, 而Toolbar 上的菜單需要根據(jù)切換的 Fra...
    Lovemma閱讀 5,580評(píng)論 1 8
  • 蕭紅落恼,是一位體驗(yàn)性、情緒性的才華橫溢的現(xiàn)代女作家离熏。她的小說(shuō)具有鮮明的文體特征佳谦,清新別致的語(yǔ)言風(fēng)格、獨(dú)特的敘事...
    彎彎wwyh閱讀 5,928評(píng)論 0 2
  • 早中晚開(kāi)會(huì)滋戳,強(qiáng)調(diào)基本面應(yīng)用钻蔑。 晚上分總請(qǐng)全公司聚餐。酒到位后新分總開(kāi)始打感情牌胧瓜。這招不錯(cuò)矢棚。
    武允兒閱讀 213評(píng)論 0 0