Skip to content

Instantly share code, notes, and snippets.

@jesseky
Created November 5, 2016 17:10
Show Gist options
  • Save jesseky/ab876a966f6217f1b1f3870de062acdd to your computer and use it in GitHub Desktop.
Save jesseky/ab876a966f6217f1b1f3870de062acdd to your computer and use it in GitHub Desktop.
swift3 post/upload file example
//
// 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