管道破裂时如何处理AJAX响应?

时间:2018-08-22 11:04:59

标签: ajax jquery-file-upload jqxhr

我有一个(Spring Boot 1.5)REST服务器来处理文件上载(import glob, shutil, os, zipfile, send2trash source = '/my/build/location' target = '/my/directory' def getLatestBuild(source, target): list_of_files = glob.glob(source + '/*.zip') latest_file = max(list_of_files, key = os.path.getctime) print(latest_file + '\n\nDownloading\n\n----------') shutil.copy(latest_file, target) return latest_file def change_dir(latest_file): directory, file = os.path.split(latest_file) target_build = os.path.join(target, file) return target_build def extractZip(target_build): zip_ref = zipfile.ZipFile(target_build, 'r') print('Unzipping' + target_build + '\n\n----------') zip_ref.extractall(target) print('file has been extracted\n\n---------') zip_ref.close() send2trash.send2trash(target_build) print(target_build + ' has been sent to trash') latest_file = getLatestBuild(source, target) target_build = change_dir(latest_file) extractZip(target_build) )和一个使用jQuery fileupload的JS客户端。在大多数情况下,它可以正常工作,但是当我要上传更大的文件(大约4MB)时,服务器会发现该文件超出了限制,并发送回包含错误消息的响应。

但是,服务器似乎停止读取请求(这是正确的),这导致客户端的管道中断。在这种情况下,将不处理响应。使用以下内容的multipart/form-data调用fail回调(data.jqXHR未定义):

data.response

使用{"readyState":0,"responseText":"","status":0,"statusText":"error"} 进行呼叫时,结果为:

curl

因此返回了一个响应,但是它似乎被JS客户端忽略了。即使请求仅部分发送,是否有让jQuery处理响应的选项?

顺便说一句:更奇怪的是,在这种情况下,我在服务器日志中看到请求重复多次,也许是JS中的一种重试机制?

2 个答案:

答案 0 :(得分:1)

  

是否有让jQuery处理响应的选项,即使   请求仅部分发送?

简短回答

否,浏览器使用XMLHttpRequest和Fetch API,根据规范,这被视为网络错误,并且网络错误有意为空。

CURL不按照XMLHttpRequest规范处理响应。

长答案

模拟服务器

读取请求的ReadableStream并中途取消:

const http = require('http');

const server = http.createServer((req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Content-Type', 'text/plain');

    //Close Request ReadableStream Prematurely
    //to simulate close pipe on exceed file size
    if (req.url === '/data' && req.method === 'POST') {
        console.log('simulating...');

        let i = 0;
        req.on('data', chunk => {
            if (i++ === 10)
                req.destroy('broken pipe');
        });
    }

    res.end('fooby\n');
}).listen(8080);

客户端测试

方法1:XMLHttpRequests

我仔细检查了每个事件,没有迹象表明已发送字节。如果我们确实有一个Sent bytes值,应该在loaded中,那么我们可以知道是否在中途取消了该请求以处理这种情况而没有响应:

let req = new XMLHttpRequest();
req.open('POST', 'http://localhost:8080/data');
    req.onloadstart = function (event) {
            console.log(event);
    };
    req.onprogress = function (event) {
            console.log(event);
    };
    req.onabort = function (event) {
            console.log(event);
    };
    req.onerror = function (event) {
            console.log(event);
    };
    req.onload = function (event) {
            console.log(event);
    };
    req.ontimeout = function (event) {
            console.log(event);
    };
    req.onloadend = function (event) {
            console.log(event);
    };
    req.onreadystatechange = function (event) {
            console.log(event);
    };
req.send(new ArrayBuffer(100000000));

不幸的是,什么都没有。

  

只读XMLHttpRequest.status属性返回数字   XMLHttpRequest响应的状态码。状态将是   无符号的短。在请求完成之前,状态值   将为0。值得注意的是,浏览器在以下状态中报告状态为0:   还是XMLHttpRequest错误。

来自XMLHttpRequest specification

  

类型为“错误”的响应称为网络错误。

     

网络错误是响应,其状态始终为0,状态消息   始终为空字节序列,标头列表始终为空,正文   始终为null,预告片始终为空。

方法2:获取API

我希望拦截一个低级的ReadableStream并得到一些东西,但是不幸的是,在网络错误时未调用resolve回调:

fetch('http://localhost:8080/data', {
        method: 'POST',
        body: new ArrayBuffer(100000000),
        mode: 'cors'
}).then(resp => {
        console.log(resp);
        //hopefully we can get readable stream here
        //...nope, networkerrors do not trigger resolve
}).catch(error => {
        console.log(error);//TypeError: "NetworkError when attempting to fetch resource."
}).then(retry => {
        console.log(retry);
});
  

当出现网络错误时,fetch()承诺会拒绝并返回TypeError   ,尽管这通常意味着权限问题或   类似。准确检查成功的fetch()将包括   检查承诺是否已解决,然后检查Response.ok   属性的值为true。 HTTP状态404不   构成网络错误

Fetch Documentation

Fetch Specification

浏览器不会将此视为HTTP错误,而是网络错误,因此不会转发与用户代码相关的任何HTTP。

结论

XHR和Fetch规范指出,网络错误被视为空响应。

答案 1 :(得分:0)

您是否尝试过jQuery $ .post处理失败响应?

$.post('server.php', {deviceId: id})
.done( function(msg) { ... } )
.fail( function(xhr, textStatus, errorThrown) {
    console.log(xhr.responseText);
});