把它在您的評論如下,你告訴我們,你使用的是$_FILES
語法來檢索文件。這意味着你想創建一個multipart/form-data
請求。該過程基本上是:
指定您的multipart/form-data
請求的邊界。
指定請求的Content-Type
指定它multipart/form-data
以及邊界是什麼。
創建請求的主體,分離各個組件(每個發佈的值以及每個上傳之間)。
有關更多詳細信息,請參見RFC 2388。不管怎樣,在斯威夫特3,這可能是這樣的:
/// Create request
///
/// - parameter userid: The userid to be passed to web service
/// - parameter password: The password to be passed to web service
/// - parameter email: The email address to be passed to web service
///
/// - returns: The `URLRequest` that was created
func createRequest(userid: String, password: String, email: String) throws -> URLRequest {
let parameters = [
"user_id" : userid,
"email" : email,
"password" : password] // build your dictionary however appropriate
let boundary = generateBoundaryString()
let url = URL(string: "https://example.com/imageupload.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let path1 = Bundle.main.path(forResource: "image1", ofType: "png")!
request.httpBody = try createBody(with: parameters, filePathKey: "file", paths: [path1], boundary: boundary)
return request
}
/// Create body of the `multipart/form-data` request
///
/// - parameter parameters: The optional dictionary containing keys and values to be passed to web service
/// - parameter filePathKey: The optional field name to be used when uploading files. If you supply paths, you must supply filePathKey, too.
/// - parameter paths: The optional array of file paths of the files to be uploaded
/// - parameter boundary: The `multipart/form-data` boundary
///
/// - returns: The `Data` of the body of the request
private func createBody(with parameters: [String: String]?, filePathKey: String, paths: [String], boundary: String) throws -> Data {
var body = Data()
if parameters != nil {
for (key, value) in parameters! {
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.append("\(value)\r\n")
}
}
for path in paths {
let url = URL(fileURLWithPath: path)
let filename = url.lastPathComponent
let data = try Data(contentsOf: url)
let mimetype = mimeType(for: path)
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(filename)\"\r\n")
body.append("Content-Type: \(mimetype)\r\n\r\n")
body.append(data)
body.append("\r\n")
}
body.append("--\(boundary)--\r\n")
return body
}
/// Create boundary string for multipart/form-data request
///
/// - returns: The boundary string that consists of "Boundary-" followed by a UUID string.
private func generateBoundaryString() -> String {
return "Boundary-\(UUID().uuidString)"
}
/// Determine mime type on the basis of extension of a file.
///
/// This requires `import MobileCoreServices`.
///
/// - parameter path: The path of the file for which we are going to determine the mime type.
///
/// - returns: Returns the mime type if successful. Returns `application/octet-stream` if unable to determine mime type.
private func mimeType(for path: String) -> String {
let url = URL(fileURLWithPath: path)
let pathExtension = url.pathExtension
if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as NSString, nil)?.takeRetainedValue() {
if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
return mimetype as String
}
}
return "application/octet-stream"
}
有了:
extension Data {
/// Append string to Data
///
/// Rather than littering my code with calls to `data(using: .utf8)` to convert `String` values to `Data`, this wraps it in a nice convenient little extension to Data. This defaults to converting using UTF-8.
///
/// - parameter string: The string to be added to the `Data`.
mutating func append(_ string: String, using encoding: String.Encoding = .utf8) {
if let data = string.data(using: encoding) {
append(data)
}
}
}
或者,斯威夫特2:
/// Create request
///
/// - parameter userid: The userid to be passed to web service
/// - parameter password: The password to be passed to web service
/// - parameter email: The email address to be passed to web service
///
/// - returns: The NSURLRequest that was created
func createRequest (userid userid: String, password: String, email: String) -> NSURLRequest {
let param = [
"user_id" : userid,
"email" : email,
"password" : password] // build your dictionary however appropriate
let boundary = generateBoundaryString()
let url = NSURL(string: "https://example.com/imageupload.php")!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let path1 = NSBundle.mainBundle().pathForResource("image1", ofType: "png") as String!
request.HTTPBody = createBodyWithParameters(param, filePathKey: "file", paths: [path1], boundary: boundary)
return request
}
/// Create body of the multipart/form-data request
///
/// - parameter parameters: The optional dictionary containing keys and values to be passed to web service
/// - parameter filePathKey: The optional field name to be used when uploading files. If you supply paths, you must supply filePathKey, too.
/// - parameter paths: The optional array of file paths of the files to be uploaded
/// - parameter boundary: The multipart/form-data boundary
///
/// - returns: The NSData of the body of the request
func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, paths: [String]?, boundary: String) -> NSData {
let body = NSMutableData()
if parameters != nil {
for (key, value) in parameters! {
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(value)\r\n")
}
}
if paths != nil {
for path in paths! {
let url = NSURL(fileURLWithPath: path)
let filename = url.lastPathComponent
let data = NSData(contentsOfURL: url)!
let mimetype = mimeTypeForPath(path)
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename!)\"\r\n")
body.appendString("Content-Type: \(mimetype)\r\n\r\n")
body.appendData(data)
body.appendString("\r\n")
}
}
body.appendString("--\(boundary)--\r\n")
return body
}
/// Create boundary string for multipart/form-data request
///
/// - returns: The boundary string that consists of "Boundary-" followed by a UUID string.
func generateBoundaryString() -> String {
return "Boundary-\(NSUUID().UUIDString)"
}
/// Determine mime type on the basis of extension of a file.
///
/// This requires MobileCoreServices framework.
///
/// - parameter path: The path of the file for which we are going to determine the mime type.
///
/// - returns: Returns the mime type if successful. Returns application/octet-stream if unable to determine mime type.
func mimeTypeForPath(path: String) -> String {
let url = NSURL(fileURLWithPath: path)
let pathExtension = url.pathExtension
if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension! as NSString, nil)?.takeRetainedValue() {
if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
return mimetype as String
}
}
return "application/octet-stream";
}
和:
extension NSMutableData {
/// Append string to NSMutableData
///
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
///
/// - parameter string: The string to be added to the `NSMutableData`.
func appendString(string: String) {
let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
appendData(data!)
}
}
有所有這些,你現在需要提交這個請求。我建議不要在你的問題中使用同步技術。你應該這樣做異步。例如,在URLSession
,斯威夫特3,你會做這樣的事情:
let request: URLRequest
do {
request = try createRequest(userid: userid, password: password, email: email)
} catch {
print(error)
return
}
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
// handle error here
print(error!)
return
}
// if response was JSON, then parse it
do {
let responseDictionary = try JSONSerialization.jsonObject(with: data!)
print("success == \(responseDictionary)")
// note, if you want to update the UI, make sure to dispatch that to the main queue, e.g.:
//
// DispatchQueue.main.async {
// // update your UI and model objects here
// }
} catch {
print(error)
let responseString = String(data: data!, encoding: .utf8)
print("responseString = \(responseString)")
}
}
task.resume()
或者,雨燕2再現:
let request = createRequest(userid: userid, password: password, email: email)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
if error != nil {
// handle error here
print(error)
return
}
// if response was JSON, then parse it
do {
if let responseDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
print("success == \(responseDictionary)")
// note, if you want to update the UI, make sure to dispatch that to the main queue, e.g.:
//
// dispatch_async(dispatch_get_main_queue()) {
// // update your UI and model objects here
// }
}
} catch {
print(error)
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
}
task.resume()
我原來的答覆是低於歷史的目的:
幾點意見:
您正在將HTTPBody
設置爲標準POST
格式(就好像它是application/x-www-form-urlencoded
請求,即使您從未指定過)。然後,您繼續放棄,並將其替換爲圖像的PNG表示的二進制數據。你大概想要發送兩個。
我們不能就恰恰是服務器期待着與澄清勸你,但是通常是multipart/form-data
,而不是application/x-www-form-urlencoded
(例如,如果它是一個PHP Web服務,它使用$_FILES
變量)。如果您正在嘗試執行multipart/form-data
,請參閱此文檔,例如POST multipart/form-data with Objective-C,例如如何操作。顯然這是Objective-C,但它說明了基本技術。
請注意,還有其他格式的其他網絡服務使用,所以我猶豫,只是假設這是預計multipart/form-data
請求。您應該確切確認服務器的預期結果。
不用說,還有其他一些問題,太(例如,你真的應該指定請求的Content-Type
,起碼,你真的不應該發出同步請求(除非你已經做這在後臺線程);我可能會建議NSURLSession
;等等)。
但主要問題是你如何填充HTTPBody
。儘管如此,我們很難幫助您進一步瞭解服務器需求。
你有什麼問題'filePathKey'我面臨同樣的問題。 – 2015-04-13 20:47:22
上傳圖片簡單... [使用Alamofire](http://stackoverflow.com/questions/32366021/alamofire-error-code-1000-the-url-does-not-point-to-a-file-url/ 36863066#36863066) – 2016-04-26 12:01:38