Created
November 5, 2016 17:10
-
-
Save jesseky/ab876a966f6217f1b1f3870de062acdd to your computer and use it in GitHub Desktop.
swift3 post/upload file example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.swift | |
// test-swift3 | |
// | |
// Created by jesse on 2016/11/5. | |
// Copyright © 2016年 jesse. All rights reserved. | |
// | |
// #!/usr/bin/env swift | |
import Foundation | |
var exit = false | |
class KFetch { | |
let session: URLSession = URLSession.shared | |
// url安全编码 | |
func escape(_ str: String) -> String { | |
let characterSet = NSMutableCharacterSet.alphanumeric() | |
characterSet.addCharacters(in: "-._ ") | |
if #available(iOS 8.3, *) { | |
return str.addingPercentEncoding(withAllowedCharacters: characterSet as CharacterSet)!.replacingOccurrences(of: " ", with: "+") | |
} | |
let length = str.characters.count | |
let num = 50 | |
let times = length > (length / num * num) ? length / num + 1 : length / num | |
var result = "" | |
for i in 0 ..< times { | |
let end = i == times - 1 ? length : num * (i+1) | |
let range = (str.characters.index(str.startIndex, offsetBy: i*num)..<str.characters.index(str.startIndex, offsetBy: end)) | |
result += str.substring(with: range).addingPercentEncoding(withAllowedCharacters: characterSet as CharacterSet)!.replacingOccurrences(of: " ", with: "+") | |
} | |
return result | |
} | |
// 转换成json字符串 | |
func jsonStringify(data: NSMutableDictionary) -> (Data?, Error?){ | |
do { | |
let json = try JSONSerialization.data(withJSONObject: data, options: JSONSerialization.WritingOptions.prettyPrinted) | |
return (json, nil) | |
} catch { | |
return (nil, error) | |
} | |
} | |
func jsonParseString(string: String) -> Any? { | |
do { | |
let data = string.data(using: String.Encoding.utf8)! | |
let json: Any! = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) | |
return json | |
} catch { | |
return nil | |
} | |
} | |
func jsonParseNSData(data: NSData) -> Any? { | |
do { | |
let json: Any! = try JSONSerialization.jsonObject(with: data as Data, options: JSONSerialization.ReadingOptions.allowFragments) | |
return json | |
} catch { | |
return nil | |
} | |
} | |
func multipartBoundary() -> String { | |
return "---------------------------KFetch3MUY8DI2L7BMRT0XDFOP" | |
} | |
// 请求 | |
func fetch(method: String, url: String, param: [String: String]?, headers: [String: String]?, options: [String:Bool]?, | |
callback: @escaping( _ r:(body: String, headers: [String:String], error: Error?, code: Int, time: Double)) -> Void ) { | |
fetchWithParamOrBody(method: method, url: url, param: param, body: nil, headers:headers, options: options, callback: callback) | |
} | |
func fetchWithParamOrBody(method: String, url: String, param: [String: String]?, body: Data?, headers: [String: String]?, options: [String:Bool]?, | |
callback: @escaping( _ r:(body: String, headers: [String:String], error: Error?, code: Int, time: Double)) -> Void ) { | |
let pos = "POST" == method || "PUT" == method // post data or put data | |
let opt = options != nil ? (escaped: options!["escaped"] ?? false, inner: options!["inner"] ?? false) : (escaped: false, inner: false) | |
let pms = param != nil ? (opt.inner ? param!["inner"] ?? "" : param!.flatMap{"\(opt.escaped ? $0 : escape($0))=\(opt.escaped ? $0 : escape($1))"}.joined(separator: "&")) : "" | |
let nsu = !pos && "" != pms ? url + (url.contains("?") ? "&" : "?") + pms : url | |
var req: URLRequest = URLRequest(url: URL(string: nsu)!) | |
req.httpMethod = method | |
if headers != nil { // 设置头部,如果有cookie,情手动调用escape编码后再传递 | |
for (k, v) in headers! { | |
req.addValue(v, forHTTPHeaderField: k) | |
} | |
} | |
if (param != nil || body != nil) && ("POST" == method || "PUT" == method) { // post data | |
req.httpBody = param != nil ? pms.data(using: String.Encoding.utf8)! : body | |
} | |
let tim = CFAbsoluteTimeGetCurrent() | |
session.dataTask(with: req, completionHandler: { (body, response, error) in | |
let b: String = body != nil ? String(data: body!, encoding: String.Encoding.utf8)! : "" | |
let h: [String:String] = response != nil ? (response as! HTTPURLResponse).allHeaderFields as! [String:String] : [:] | |
let c: Int = response != nil ? (response as! HTTPURLResponse).statusCode : 0 | |
let t: Double = CFAbsoluteTimeGetCurrent() - tim | |
// let r = (body: b, headers: h, error: error, code: c, time: t) | |
callback(body: b, headers: h, error: error, code: c, time: t) | |
}).resume() | |
} | |
// 上传文件 | |
// upload file | |
func upload(method: String, url: String, param: [String:String]?, fieldName: String, files: [String: Data]?, headers: [String: String]?, options: [String:Bool]?, | |
callback: @escaping( _ r:(body: String, headers: [String:String], error: Error?, code: Int, time: Double)) -> Void ) { | |
let bd = kf.multipartBoundary() | |
var body = Data() | |
let boundary = "--\(bd)\r\n".data(using: String.Encoding.utf8)! | |
if param != nil { | |
for (k, v) in param! { | |
body.append(boundary) | |
body.append("Content-Disposition: form-data; name=\"\(k)\"\r\n\r\n".data(using: String.Encoding.utf8)!) | |
body.append("\(v)\r\n".data(using: String.Encoding.utf8)!) | |
} | |
} | |
if files != nil { | |
for (k, v) in files! { | |
let ks = k.components(separatedBy: "\t") | |
let fileName = ks[0] | |
let fileType = ks.count>=2 ? ks[1] : "application/oct-stream" | |
body.append(boundary) | |
body.append("Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(fileName)\"\r\n".data(using: String.Encoding.utf8)!) | |
body.append("Content-Type: \(fileType)\r\n\r\n".data(using: String.Encoding.utf8)!) | |
body.append(v) | |
body.append("\r\n".data(using: String.Encoding.utf8)!) | |
} | |
} | |
if body.count > 0 { | |
body.append("--\(bd)--\r\n".data(using: String.Encoding.utf8)!) | |
} | |
var hds :[String: String] = headers != nil ? headers! : [:] | |
hds["Content-Type"] = "multipart/form-data; boundary=\(bd)" | |
fetchWithParamOrBody(method: method, url: url, param: nil, body: body, headers: hds, options: options, callback: callback) | |
} | |
} | |
// test code, preare one image, files is Dict, format like: imageName [Tab] mime => Data | |
let kf = KFetch() | |
var pm:[String: String]? = ["a": "1", "b":"2"] | |
let file = try Data(contentsOf: URL(fileURLWithPath: "/Users/jesse/Downloads/test.jpg"), options: Data.ReadingOptions.init(rawValue: String.Encoding.utf8.rawValue)) | |
kf.upload(method: "POST", url: "http://localhost/~jesse/post.php", param: pm, fieldName: "image", files: ["test.jpg\timage/jpeg": file], headers: nil, options: nil) { | |
response in | |
print(response.body) | |
exit = true | |
} | |
while !exit { | |
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.01)) | |
} | |
print("Exited.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment