使用 JustHTTP 和 Alamofire 发送两次 HTTP 帖子

Posted

技术标签:

【中文标题】使用 JustHTTP 和 Alamofire 发送两次 HTTP 帖子【英文标题】:HTTP post sent twice using both JustHTTP and Alamofire 【发布时间】:2015-10-01 16:44:44 【问题描述】:

我正在尝试使用 ios 9 中的 Swift 2 HTTP 上传(到 Windows IIS 服务器)图像和表单参数,并且由于某种原因,即使我只在按钮上调用函数之一,它也会发送两次帖子点击。

我已经检查过该按钮没有多次触发。

我正在使用基本身份验证发布到 HTTPS(我尝试过使用 HTTP 并获得相同的结果)。使用 JustHttp(0.3 版)和 Alamofire 3 都会发生这种情况。

在 Alamofire(和 JustHTTP)中观察上传进度,我可以看到它更新了 totalBytesExpectedToWrite,然后在上传的某个时刻,totalBytesExpectedToWrite 的价值翻了一番。

我已尝试调试 JustHTTP 和 Alamofire 以了解为什么会发生这种情况,但找不到发生的位置。

我使用的 JustHttp 代码是:

Just.post(
        "https://my.url.com",
        auth:("xxxxxxxx", "xxxxxxxxx"),
        timeout: 20,
        data:["Name": tfName.text! as AnyObject,
        "Email": tfEmail.text! as AnyObject,
        files:[
            "file":HTTPFile.Data("photo.jpg", imagedata!, nil)
        ],
        asyncProgressHandler: (p) in
            print(p.type) // either .Upload or .Download
            if (p.type == ProgressType.Upload)
            
                dispatch_async(dispatch_get_main_queue()) 
                    // update some UI
                    self.textView.titleLabel.text = "Sending Entry...\(Int(p.percent*100))%"
                
            
        ,
        asyncCompletionHandler: (r) in
        dispatch_async(dispatch_get_main_queue()) 
            print(r.statusCode)
        
    )

Alamofire 代码是:

Alamofire.upload(Method.POST, "https://the.url.com", multipartFormData:  multipartFormData in
        multipartFormData.appendBodyPart(data: imagedata!, name: "file", fileName: "photo.jpg", mimeType: "image/png")
        multipartFormData.appendBodyPart(data: "My Name".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name: "Name")
        multipartFormData.appendBodyPart(data: "My Email address".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name: "Email")
        ,
        encodingCompletion:  encodingResult in
            print("encoding done")
            switch encodingResult 
            case .Success(let upload, _, _):
                upload.authenticate(user: "xxxxxx", password: "xxxxxxxxxx")
                    .progress  bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
                        print("a: \(bytesWritten) b: \(totalBytesWritten) c: \(totalBytesExpectedToWrite)")

                
                upload.responseString  request, response, responseBody in
                    print(request)
                    print(response!.statusCode)
                    switch responseBody 
                    case Result.Success(let responseValue):
                        print(responseValue)

                    case Result.Failure(_, let error as NSError):
                        print(error)

                    default: break

                    
                
            case .Failure(let encodingError):
                print(encodingError)
            
    )

更新

我现在已经在没有身份验证的情况下使用 Alamofire 进行了尝试,它按预期工作,即只发送整个请求一次。

【问题讨论】:

【参考方案1】:

好的,我已经解决了这个问题。除了 auth 参数(在 Just 和 Alamofire 中)之外,我还需要添加到以下标题。我从 Alamofire 文档中获得了代码,但没有意识到我需要添加标头并包含 auth 属性。

let user = "xxxxxxx"
let password = "xxxxxxx"
let credentialData = "\(user):\(password)".dataUsingEncoding(NSUTF8StringEncoding)!
let base64Credentials = credentialData.base64EncodedStringWithOptions([])
let headers = ["Authorization": "Basic \(base64Credentials)"]

然后是 Alamofire:

Alamofire.upload(Method.POST, "https://my.url.com", headers: headers, multipartFormData: [...]

对于 JustHttp:

Just.post("https://my.url.com",
        auth:(user, password),
        headers: headers,
        [...]

为了完整起见,远程网络服务器是运行 Asp.Net C# MVC 5 的 IIS 7.5,并带有以下 Auth 操作过滤器:

public class BasicAuthenticationAttribute : ActionFilterAttribute

    public string BasicRealm  get; set; 
    protected string Username  get; set; 
    protected string Password  get; set; 

    public BasicAuthenticationAttribute(string username, string password)
    
        this.Username = username;
        this.Password = password;
    

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"];
        if (!String.IsNullOrEmpty(auth))
        
            var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
            var user = new  Name = cred[0], Pass = cred[1] ;
            if (user.Name == Username && user.Pass == Password) return;
        
        var res = filterContext.HttpContext.Response;
        res.StatusCode = 401;
        res.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"0\"", BasicRealm ?? "content.imaginecruising.co.uk"));
        res.End();
    

C# MVC 用法:

[BasicAuthenticationAttribute("myusername", "mypassword", BasicRealm = "my.domain.com")]
public ActionResult MyAction()

【讨论】:

我在基本身份验证方面遇到了同样的问题,感谢您的回答!

以上是关于使用 JustHTTP 和 Alamofire 发送两次 HTTP 帖子的主要内容,如果未能解决你的问题,请参考以下文章

在 swift 中使用 alamofire 发送 JSON 数组作为参数

一键多值的Alamofire参数

在后台接收静默推送时无法向 Alamofire 发出请求

经过身份验证的 http 请求 swift Alamofire

在 Swift 中将 Alamofire 结果解析为对象(使用:Alamofire、SwiftyJSON 和 ObjectMapper)

在同一个项目中使用 Alamofire 和 AlamofireImage