或許你已經非常了解如何利用Json上傳資料,但是不知道你是否思考過。
Json是沒辦法上傳檔案的,如果需要上傳檔案,那就需要使用其他的ContentType。
發出POST請求時,必須以某種方式對構成請求正文的數據進行編碼。
HTML表單提供了三種編碼方法。
(使用HTML表單提交以外的其他方式生成的HTTP請求也可以使用其他編碼。JSON是用於Web服務的常見格式,有些仍然使用SOAP。)
以下是很典型的multipart/form-data的樣式
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"
text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"
aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream
aωb
-----------------------------735323031399963166993862150--
對於二進製文件和文本字段,字節61 CF 89 62(aωb在UTF-8中)按字面意義發送。您可以使用驗證該信息nc -l localhost 8000 | hd,該信息表明這些字節:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150將內容類型設置為,multipart/form-data並說字段由給定的boundary字符串分隔。
multipart/form-data與往前的json略顯不同,我將拆解的部分做了一些變化。
製作一個生成parameters的funtion
static func makeParameters(_ cardID:Int,_ view:CardEditView,_ method:HTTPMethod)->[String:Any]{
var parameters:[String:Any] = [:]
let data = getViewData(view: view)
if let title = data.title {
parameters["title"] = title
}
if let description = data.description {
parameters["description"] = description
}
if method == .PUT {
parameters["_method"] = "PUT"
}
parameters["card_id"] = cardID
parameters["tag"] = data.tag
print(parameters)
return parameters
}
製作一個生成DataPaths 的 funtion
var dataPath:[String:Data] = [:]
let data = getViewData(view: view)
if let image = data.image {
let data = image.jpegData(compressionQuality: 0.1)
dataPath["image"] = data
}
return dataPath
生成 Body,並打包 parameters 與 dataPaths
private static func makeBody(_ parameters:[String:Any],_ dataPath:[String:Data],_ boundary:String)->Data{
var body = Data()
for (key, value) in parameters {
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString(string: "\(value)\r\n")
}
for (key, value) in dataPath {
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(arc4random())\"\r\n") //此處放入file name,以隨機數代替,可自行放入
body.appendString(string: "Content-Type: image/png\r\n\r\n") //image/png 可改為其他檔案類型 ex:jpeg
body.append(value)
body.appendString(string: "\r\n")
}
body.appendString(string: "--\(boundary)--\r\n")
return body
}
在這裡你不能發現boundary,這個東西類似,分隔線。
你需要特別注意,boundary必須都是一樣的,另外,設置content Type時,是要帶給header的。
所以在生成request時,可以額外打包給他。