如何使用Alamofire在Swift中上传带参数的图像

21

我正在使用Swift开发iPhone应用程序,并且使用Alamofire框架来处理HTTP请求。我使用Alamofire.request进行POST、GET等请求,代码如下:

Alamofire.request(.POST, myURL , parameters: ["a": "1", "b" : "2" ])
        .response { (request, response, data, error) in
}  

我使用 Alamofire.upload 将图片上传到服务器:

Alamofire.upload(.POST, uploadURL , fileURL)

两种方法都可以正常工作,但现在我想上传图像并同时发送一些参数,我的内容类型应该是 multipart/form-data,而 Alamofire.upload 不接受参数。

关于这个问题,SO 上有两个更多的问题与 swift 相关,其中 first one 没有使用 Alamofire(真的,为什么不使用?),在 second one 中,mattt(Alamofire 开发人员)建议使用编码参数。

我查看了他的示例,但仍然无法弄清楚如何实现。

请问有人能帮助我解决这个问题吗?

谢谢!:)


这是我找到的解决方案,发布在另一个问题上: https://dev59.com/UV8e5IYBdhLWcg3wEXFi#26747857 - antiblank
Reza_Rg,你能帮我吗?我也使用'Alamofire.upload(.POST, uploadURL , fileURL)',但是我该如何构建php文件来接收文件呢?通过.POST发送的文件在我的php文件中的哪里可用? - gutenmorgenuhu
@Reza_Rg,你解决了你的问题吗?如果是这样,能否分享一下答案? - user2363025
@user2363025 是的,但我最终改变了Alamofire库中的一些代码,我知道这不是正确的做法。 - Reza_Rg
6个回答

25

您可以使用以下代码来使用 Alamofire 3.0+

func uploadImageAndData(){
    //parameters
    let gender    = "M"
    let firstName = "firstName"
    let lastName  = "lastName"
    let dob       = "11-Jan-2000"
    let aboutme   = "aboutme"
    let token     = "token"

    var parameters = [String:AnyObject]()
    parameters = ["gender":gender,
                  "firstName":firstName,
                  "dob":dob,
                  "aboutme":about,
                  "token":token,
                  "lastName":lastName]

    let URL = "http://yourserviceurl/"
    let image = UIImage(named: "image.png")

    Alamofire.upload(.POST, URL, multipartFormData: {
        multipartFormData in

        if let imageData = UIImageJPEGRepresentation(image, 0.6) {
            multipartFormData.appendBodyPart(data: imageData, name: "image", fileName: "file.png", mimeType: "image/png")
        }

        for (key, value) in parameters {
            multipartFormData.appendBodyPart(data: value.dataUsingEncoding(NSUTF8StringEncoding)!, name: key)
        }
    }, encodingCompletion: {
        encodingResult in

        switch encodingResult {
        case .Success(let upload, _, _):
            print("s")
            upload.responseJSON { 
                response in
                print(response.request)  // original URL request
                print(response.response) // URL response
                print(response.data)     // server data
                print(response.result)   // result of response serialization

                if let JSON = response.result.value {
                    print("JSON: \(JSON)")
                }
            }
        case .Failure(let encodingError):
            print(encodingError)
        }
    })
}

HTTP错误415,不支持的媒体类型,请检查图像类型@chamathjeevan - amit gupta
1
如果在以下参数中存在“image”键["gender":gender,"firstName":firstName,"dob":dob,"aboutme":aboutme,"token":token,"lastName":lastName, "image": imageData],那么multipartFormData.appendBodyPart(data: imageData, name: "image", fileName: "file.png", mimeType: "image/png")将会附加在参数中吗? - Deepak Thakur
@amitgupta,希望你已经看到了我上面的问题。 - Deepak Thakur
非常好,有一个问题。如果我从相机拍照并在UIImage上执行UIImagePNGRepresentation函数,如何保留方向? - Shayan C
即使根据Swift 3的语法进行更改,它仍无法在Swift 3中工作。 - Harish Singh
Great@Dilip Tiwari - Harish Singh

4

SWIFT 2 AlamoFire 简单图片上传 (REST API)

@amit gupta,看起来你的答案存在很大的开销。AlamoFire提供了许多简化的解决方案。Alamofire.request方法包含几个简化重载,可用于简单上传。通过使用 Alamofire.request 方法,开发者可以摆脱编码开销。

HTTP状态码415表示未指定正确的媒体类型。

请查看下面的解决方案。

import UIKit
import Alamofire

class ViewController: UIViewController {

    @IBOutlet var imageView: UIImageView!
    @IBOutlet var btnUpload: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func successDataHandler(responseData:String){

        print ("IMAGE UPLOAD SUCCESSFUL    !!!")

    }

    func failureDataHandler(errorData:String){

        print ("  !!!   IMAGE UPLOAD FAILURE   !!! ")

    }

    @IBAction func actionUpload(sender: AnyObject) {

        let URL = "http://m8coreapibeta.azurewebsites.net/api/cards/SaveImages"

        let postDataProlife:[String:AnyObject] = ["CardId":(dataCardDetail?.userId)!,"ImageType":1,"ImageData":imageView.image!]

        uplaodImageData(URL, postData: postDataProlife, successHandler: successDataHandler, failureHandler: failureDataHandler)
    }

    func uplaodImageData(RequestURL: String,postData:[String:AnyObject]?,successHandler: (String) -> (),failureHandler: (String) -> ()) -> () {

        let headerData:[String : String] = ["Content-Type":"application/json"]

        Alamofire.request(.POST,RequestURL, parameters: postData, encoding: .URLEncodedInURL, headers: headerData).responseString{ response in
            switch response.result {
            case .Success:
                print(response.response?.statusCode)
                successHandler(response.result.value!)
            case .Failure(let error):
                failureHandler("\(error)")
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

3

使用Alamofire 4的Swift 4

let isConnected = connectivity.isConnectedToInternet()

  func updateProfile(firstName:String,lastName:String ,imageData:Data?,completion: @escaping (isValidUser)->()) {


    if self.isConnected {

        var parameters : [String:String] = [:]
        parameters["auth_key"] = loginUser?.authKey!
        parameters["first_name"] = firstName
        parameters["last_name"] = lastName

        let url = "\(baseUrl)\(basicAuthenticationUrl.updateProfile)"
        print(url)


        Alamofire.upload(multipartFormData: { (multipartFormData) in
            for (key, value) in parameters {
                multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
            }

            if let data = imageData {
                multipartFormData.append(data, withName: "image_url", fileName: "image.png", mimeType: "image/png")
            }

        }, usingThreshold: UInt64.init(), to: url, method: .post) { (result) in
            switch result{
            case .success(let upload, _, _):
                upload.responseJSON { response in
                    print("Succesfully uploaded  = \(response)")
                    if let err = response.error{

                        print(err)
                        return
                    }

                }
            case .failure(let error):
                print("Error in upload: \(error.localizedDescription)")

            }
        }
    }

}

3

使用Swift 3.0的Alamofire

Alamofire.upload(multipartFormData: { multipartFormData in
    var index = 1
    for image in imageArray {
        let imageData: Data = (UIImageJPEGRepresentation(image, 1.0) as Data?)!

        multipartFormData.append(imageData, withName: "home-\(index)", fileName: "home-\(index)", mimeType: "image/jpeg")

        index += 1
    }
    }, with: requestName, encodingCompletion: { result in
        switch result {
        case .success(let upload, _, _):

            upload.responseJSON { response in
                print("Image(s) Uploaded successfully:\(response)")
            }
        case .failure(let encodingError):
            print("encodingError:\(encodingError)")
        }
})

我的问题是图片名称和目录,如何在相册目录中实现图片及其名称? - Saeed Rahmatolahi

0

使用Swift 2.0的Alamofire,只需复制并粘贴以下代码。这里假设m是来自服务器的JSON响应。

 func uploadImageRemote (imageData : NSData?) -> Dictionary <String,AnyObject>{
    var imageDictionary = Dictionary<String,AnyObject>()

      var tokenHeaders:[String:String]! = ["x-access-token":Constants.kUserDefaults.stringForKey("userToken")!]
    Alamofire.upload(
        .POST,
        "http://52.26.230.146:3300/api/profiles/imageUpload",headers:tokenHeaders,
        multipartFormData: { multipartFormData in
            multipartFormData.appendBodyPart(data: imageData!, name: "upload", fileName: "imageFileName.jpg", mimeType: "image/jpeg")
        },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):
                upload.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
                    print("Uploading Avatar \(totalBytesWritten) / \(totalBytesExpectedToWrite)")
                    dispatch_async(dispatch_get_main_queue(),{

                    })
                }
                upload.responseJSON { response in
                    guard response.result.error == nil else {
                        print("error calling GET \(response.result.error!)")
                        return
                    }

                    if let value = response.result.value {
                       print("Success JSON is:\(value)")
                        if let result = value as? Dictionary<String, AnyObject> {
                            imageDictionary["imageUrl"] = result["url"]
                        }
                    }

                    dispatch_async(dispatch_get_main_queue(),{
                        //Show Alert in UI
                        print("Avatar uploaded");
                    })
                }

            case .Failure(let encodingError):
                //Show Alert in UI
                print("Avatar not uploaded \(encodingError)");
            }
        }
    );



return imageDictionary
}

-2
要使用编码参数,请创建一个ParameterEncoding变量,为其分配一个编码类型(枚举包括.JSON、.URL),然后使用encode函数与您的NSURLRequest和参数一起使用。此函数返回一个由两个元素组成的元组,第一个元素是生成的NSURLRequest,第二个元素是可能的NSError。
以下是我在项目中需要自定义标头时如何使用它的示例。
 var parameterEncoding:ParameterEncoding!
    switch method {
        case .POST, .PUT :
            parameterEncoding = ParameterEncoding.JSON
        default :
            parameterEncoding = ParameterEncoding.URL
    }
    var alamoRequest = Alamofire.Manager.sharedInstance.request(parameterEncoding.encode(mutableURLRequest, parameters: parameters).0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接