Arn*_*ter 8 ajax jqxhr jquery-file-upload
我有一个(Spring Boot 1.5)REST服务器处理文件uploads(multipart/form-data)和一个使用jQuery fileupload的JS客户端.在大多数情况下它工作正常,但是当我想上传一个更大的文件(大约4MB)时,服务器会发现它超出了限制并发回包含错误消息的响应.
然而,似乎服务器停止读取请求(当然是正确的),这导致客户端管道损坏.在这种情况下,不处理响应.该fail回调函数调用的内容如下data.jqXHR(data.response未定义):
{"readyState":0,"responseText":"","status":0,"statusText":"error"}
Run Code Online (Sandbox Code Playgroud)
使用时进行呼叫curl,结果是:
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
curl: (55) Send failure: Broken pipe
{"files":[{"size":3863407,"error":"upload_uploadSizeExceeded"}]}
Run Code Online (Sandbox Code Playgroud)
所以返回了一个响应,但JS客户端似乎忽略了它.有没有选项让jQuery处理响应,即使请求只是部分发送?
顺便说一句:更奇怪的是,我在服务器日志中看到这样的请求重复了几次,这可能是JS中的一种重试机制?
即使请求仅部分发送,是否有任何选项可以让 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);
Run Code Online (Sandbox Code Playgroud)
我仔细检查了每个事件,没有发现发送字节的迹象。如果我们确实有一个 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));
Run Code Online (Sandbox Code Playgroud)
不幸的是,什么也没有。
只读 XMLHttpRequest.status 属性返回 XMLHttpRequest 响应的数字状态代码。状态将是一个未签名的短。在请求完成之前,status 的值为 0。值得注意的是,如果 XMLHttpRequest 错误,浏览器也会报告 status 0。
类型为“错误”的响应称为网络错误。
网络错误是指状态始终为 0 的响应,状态消息始终为空字节序列,标头列表始终为空,正文始终为空,尾部始终为空。
我希望拦截一个低级 ReadableStream 并获取一些内容,但不幸的是,在网络错误时不会调用解析回调:
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);
});
Run Code Online (Sandbox Code Playgroud)
当遇到网络错误时, fetch() Promise 会拒绝并返回 TypeError,尽管这通常意味着权限问题或类似问题。对成功 fetch() 的准确检查包括检查 Promise 是否已解析,然后检查 Response.ok 属性的值为 true。HTTP 状态 404 并不构成网络错误。
浏览器不会将此视为 HTTP 错误,而是网络错误,因此不会转发与用户代码相关的任何 HTTP。
XHR 和 Fetch 规范规定网络错误将作为空响应进行处理。