Как отправить файл изображения на сервер, используя функцию post с помощью быстрого 4 [дубликата]

Рекомендация W3Schools:

поместить overflow: auto в родительский элемент, и он «окрасит» весь фон, включая поля элементов. Также плавающие элементы будут оставаться внутри границы.

http://www.w3schools.com/css/tryit.asp?filename=trycss_layout_clearfix

58
задан Jojodmo 28 April 2016 в 00:12
поделиться

3 ответа

В своем комментарии ниже вы сообщаете нам, что используете синтаксис $_FILES для извлечения файлов. Это означает, что вы хотите создать запрос multipart/form-data. Процесс в основном:

  1. Укажите границу для вашего запроса multipart/form-data.
  2. Укажите Content-Type запроса, который указывает, что он multipart/form-data и что граница.
  3. Создает тело запроса, разделяя отдельные компоненты (каждый из опубликованных значений, а также между каждой загрузкой).

Подробнее см. RFC 2388 . В любом случае, в Swift 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)
        }
    }
}

Или, в Swift 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 в Swift 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()

Или, для версии Swift 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()

Мой оригинал ниже для исторических целей:


Несколько наблюдений:

  1. Вы устанавливаете HTTPBody как стандартный формат POST (как если бы он был запросом application/x-www-form-urlencoded, даже если вы этого не указали). Затем вы можете отказаться от этого и заменить его двоичными данными PNG-представления изображения. Вы, вероятно, хотели отправить оба.
  2. Мы не можем дать вам разъяснения относительно того, что ожидает сервер, но часто это multipart/form-data, а не application/x-www-form-urlencoded (например, если это веб-служба PHP, он использует переменную $_FILES). Если вы пытаетесь сделать multipart/form-data, см. Это POST multipart / form-data с Objective-C , например, как это сделать. Ясно, что это Objective-C, но это иллюстрирует основную технику. Обратите внимание: существуют и другие форматы, используемые другими веб-службами, поэтому я смущаюсь просто предположить, что это ожидает запрос multipart/form-data. Вы должны точно подтвердить, что ожидает сервер.

Излишне говорить, что есть и другие проблемы (например, вы действительно должны указать Content-Type запроса, по крайней мере; вы действительно не должны выдавать синхронный запрос (если вы уже делаете это в фоновом потоке), я бы посоветовал NSURLSession и т. д.).

Но основная проблема заключается в том, как вы заселяете HTTPBody. Нам тяжело помочь вам в дальнейшем без большей ясности относительно того, что требует сервер.

119
ответ дан Rob 19 August 2018 в 03:11
поделиться
  • 1
    стань! Я использую $ _File! что я должен делать? – user3426109 2 October 2014 в 21:02
  • 2
    @ user3426109 Вы должны выполнить запрос multipart/form-data. См. Образец кода в пересмотренном ответе – Rob 3 October 2014 в 05:04
  • 3
    @NicolasMiari - это Swift 2. Как говорится в комментарии для mimeTypeForPath, вам нужно MobileCoreServices. Итак, вверху файла, сделайте import MobileCoreServices. – Rob 22 December 2015 в 09:15
  • 4
    @luke - Это вопрос мнения, но похоже, что клиентское приложение немного запуталось в деталях реализации архитектуры заднего конца. Вероятно, вы также имеете дело с двумя системами аутентификации и двумя точками отказа. Вероятно, я склоняюсь к одной конечной точке приложения, и веб-служба управляет хранилищем изображений. – Rob 10 June 2017 в 16:26
  • 5
    @ KrutikaSonawala. Выше я предположил, что у вас есть веб-сервис, который написал ответы JSON. (Это один из самых надежных способов заставить веб-службу возвращать анализируемый ответ на клиентское приложение.) Возможно, ваш веб-сервис не предназначен для возврата ответа JSON. Или, возможно, у вас была ошибка в вашем веб-сервисе, что помешало ему создать правильный ответ JSON. Я не могу диагностировать это на основании вашего комментария. Если вышеупомянутое не ясно, я предлагаю вам опубликовать свой собственный вопрос, показывая нам, что вы сделали, что вы ожидали в ответ, и то, что вы действительно получили в ответ. – Rob 12 January 2018 в 07:19

Спасибо, @Rob, ваш код работает нормально, но в моем случае я возвращаю изображение из галереи и беру имя изображения с помощью кода:

let filename = url.lastPathComponent

Но этот код, отображающий расширение изображения как .JPG (в заглавной букве), но сервер не принимает расширения в capital письме, поэтому я изменил свой код как:

 let filename =  (path.lastPathComponent as NSString).lowercaseString

, и теперь мой код работает нормально.

Спасибо:)

1
ответ дан itsji10dra 19 August 2018 в 03:11
поделиться

Теперь AlamoFire поддерживает Multipart:

https://github.com/Alamofire/Alamofire#uploading-multipartformdata

Вот сообщение в блоге с образцом проект, касающийся использования Multipart с AlamoFire.

http://www.thorntech.com/2015/07/4-essential-swift-networking-tools-for-working-with-rest -apis /

Соответствующий код может выглядеть примерно так (если вы используете AlamoFire и SwiftyJSON):

func createMultipart(image: UIImage, callback: Bool -> Void){
    // use SwiftyJSON to convert a dictionary to JSON
    var parameterJSON = JSON([
        "id_user": "test"
    ])
    // JSON stringify
    let parameterString = parameterJSON.rawString(encoding: NSUTF8StringEncoding, options: nil)
    let jsonParameterData = parameterString!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
    // convert image to binary
    let imageData = UIImageJPEGRepresentation(image, 0.7)
    // upload is part of AlamoFire
    upload(
        .POST,
        URLString: "http://httpbin.org/post",
        multipartFormData: { multipartFormData in
            // fileData: puts it in "files"
            multipartFormData.appendBodyPart(fileData: jsonParameterData!, name: "goesIntoFile", fileName: "json.txt", mimeType: "application/json")
            multipartFormData.appendBodyPart(fileData: imageData, name: "file", fileName: "iosFile.jpg", mimeType: "image/jpg")
            // data: puts it in "form"
            multipartFormData.appendBodyPart(data: jsonParameterData!, name: "goesIntoForm")
        },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):
                upload.responseJSON { request, response, data, error in
                    let json = JSON(data!)
                    println("json:: \(json)")
                    callback(true)
                }
            case .Failure(let encodingError):
                callback(false)
            }
        }
    )
}

let fotoImage = UIImage(named: "foto")
    createMultipart(fotoImage!, callback: { success in
    if success { }
})
13
ответ дан Robert Chen 19 August 2018 в 03:11
поделиться
  • 1
    Большое спасибо, смотрел только на это: D: D !!! – Dark Innocence 10 April 2017 в 11:25
Другие вопросы по тегам:

Похожие вопросы: