7

我正在尝试让 iOS 6 使用 XMLHttpRequest POST 上传图像。这适用于桌面和 Android 网络浏览器,但在 iOS 6 上,我在发布到的页面上收到错误:“请求正文流已用尽”。(使用带有 Safari Web Inspector 的 iOS 模拟器)。

这是页面的基本代码:

function fileSelected() {
    var file = document.getElementById('fileToUpload').files[0];
    if (file) {
        var fileSize = 0;
        if (file.size > 1024 * 1024)
            fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
        else
            fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
        document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
        document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
        document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
    }
}
function uploadFile() {
    var fd = new FormData();
    fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
    var xhr = new XMLHttpRequest();
    xhr.upload.addEventListener("progress", uploadProgress, false);
    xhr.addEventListener("load", uploadComplete, false);
    xhr.addEventListener("error", uploadFailed, false);
    xhr.addEventListener("abort", uploadCanceled, false);
    xhr.open("POST", "/UploadHandler.ashx");
    xhr.send(fd);
}
function uploadProgress(evt) {
    if (evt.lengthComputable) {
        var percentComplete = Math.round(evt.loaded * 100 / evt.total);
        document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
        document.getElementById('prog').value = percentComplete;
    }
    else {
        document.getElementById('progressNumber').innerHTML = 'unable to compute';
    }
}
function uploadComplete(evt) {
    /* This event is raised when the server send back a response */
    alert(evt.target.responseText);
}
function uploadFailed(evt) {
    alert("There was an error attempting to upload the file.");
}
function uploadCanceled(evt) {
    alert("The upload has been canceled by the user or the browser dropped the connection.");
}

在任何其他浏览器上执行此操作时,处理程序会正确返回并上传文件。但是,对于 iOS,ashx 页面出现错误“请求正文流已用尽”。

这是检查器的屏幕截图:

Request Body Stream Exhausted

有任何想法吗?

UPDATE: This issue only occurs when NTLM/Windows authentication is enabled for the application in IIS. With forms or anonymous authentication, the upload works fine.

Thanks,

John

4

3 回答 3

5

In iOS 6, Safari sends the file with the initial post, including the file. That means the file stream is at the end, or "exhausted."

However, with NTLM, it will get a 401 challenge in response, and then have to resend the post with the authentication information. Since it does not reset the file stream, it is unable to send the file again with the second post. You can see this in the IIS logs.

As far as I know, there is no particularly good way around it. I am changing my mobile app, so that it uses form authentication. I direct the mobile app to a separate login app on the same server, which is set to use Windows Authentication. The login app can then redirect back to the main app with a form authentication cookie, and all is well again.

You have to set the machine key on both apps in the web.config file, so that both are using the same keys for encryption and validation.

The code on the login app is as simple as

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ 
Handles Me.Load
    With HttpContext.Current.User.Identity
        If .IsAuthenticated Then
            Dim sUser As String = .Name.ToLower.Trim
            FormsAuthentication.RedirectFromLoginPage(s, False)
        End If
    End With
End Sub
于 2012-10-11T18:25:18.610 回答
0

I solved the issue by not setting the self-defined HTTP Authenticate Head on iOS 7 and iOS 8. (At first, our service use the self-defined value for the Authenticate Head). And after the challenge being handled by the delegate, the request will have the "Authenticate: NTLMxxx automatically" header automatically. And the Put and POST works again.

于 2014-12-24T06:52:14.060 回答
0

This error Comes on IOS but you can use different approach like change your code line in formdata where you appending the file

var fd = new FormData();

fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);

to the below line basically don't append the file control but use the base64 image data

var reader = new FileReader();

reader.readAsDataURL(opmlFile.files[0]);

reader.onload = function () {

    var base64DataImg = reader.result;            

    base64DataImg = base64DataImg.replace('data:'imagetype';base64,', '');      

}
于 2016-12-23T06:31:10.343 回答