Skip to content

Commit

Permalink
add net error code (#332)
Browse files Browse the repository at this point in the history
* feat error code

* 分片上传单片出现异常的case

* browser timeout and test case

* add node timeout error case

* add request net err case

* add note about TypeError

* opti error code

* rm browser default timeout can use fetch

* add note about fetch err and xmlhttprequset err

* add note about err code

* change let to var

* fix browser timeout test case

* fix error code test case

* fix wrapper test case

* fix review code

* code format

* 分片上传增加init upload part,complete3个情况的 requestId (#335)

* 添加 分片上传返回request id   初始化和 单片上传

* add requestid with multipart and test case

* fix test ase

* opti: test case assert

* fix node test case

* add multipart doc

* opti: test case

* case 判空

* fix test case

* fix test case

* feat error code

* 分片上传单片出现异常的case

* browser timeout and test case

* add node timeout error case

* add request net err case

* add note about TypeError

* opti error code

* rm browser default timeout can use fetch

* add note about fetch err and xmlhttprequset err

* add note about err code

* change let to var

* fix browser timeout test case

* fix error code test case

* fix review code

* code format

* resolve confict
  • Loading branch information
binghaiwang authored and PeterRao committed Jan 9, 2018
1 parent ceae401 commit 2021661
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 80 deletions.
69 changes: 45 additions & 24 deletions lib/browser/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ Client.initOptions = function initOptions(options) {
region: 'oss-cn-hangzhou',
internal: false,
secure: false,
timeout: 60000, // 60s
bucket: null,
endpoint: null,
cname: false,
Expand All @@ -75,7 +74,9 @@ Client.initOptions = function initOptions(options) {
opts.accessKeyId = opts.accessKeyId.trim();
opts.accessKeySecret = opts.accessKeySecret.trim();

opts.timeout = ms(opts.timeout);
if (opts.timeout) {
opts.timeout = ms(opts.timeout);
}

if (opts.endpoint) {
opts.endpoint = setEndpoint(opts.endpoint);
Expand Down Expand Up @@ -307,17 +308,30 @@ proto.createRequest = function createRequest(params) {

proto.request = function* request(params) {
var reqParams = this.createRequest(params);
var result = yield this.urllib.request(reqParams.url, reqParams.params);
debug('response %s %s, got %s, headers: %j', params.method, reqParams.url, result.status, result.headers);
if (params.successStatuses && params.successStatuses.indexOf(result.status) === -1) {
var err = yield* this.requestError(result);
var result;
var reqErr;
try {
result = yield this.urllib.request(reqParams.url, reqParams.params);
debug('response %s %s, got %s, headers: %j', params.method, reqParams.url, result.status, result.headers);
} catch (err) {
reqErr = err;
}
var err
if (result && params.successStatuses && params.successStatuses.indexOf(result.status) === -1) {
err = yield this.requestError(result);
if (err.code === 'RequestTimeTooSkewed') {
this.amendTimeSkewed = +new Date(err.serverTime) - new Date()
return yield* this.request(params);
this.amendTimeSkewed = +new Date(err.serverTime) - new Date()
return yield this.request(params);
}
err.params = params;
} else if (reqErr) {
err = yield this.requestError(reqErr);
}

if (err) {
throw err;
}

if (params.xmlResponse) {
result.data = yield this.parseXML(result.data);
}
Expand Down Expand Up @@ -446,24 +460,31 @@ proto.parseXML = function parseXMLThunk(str) {
proto.requestError = function* requestError(result) {
var err;
if (!result.data || !result.data.length) {
// HEAD not exists resource
if (result.status === 404) {
err = new Error('Object not exists');
err.name = 'NoSuchKeyError';
err.status = 404;
err.code = 'NoSuchKey';
} else if (result.status === 412) {
err = new Error('Pre condition failed');
err.name = 'PreconditionFailedError';
err.status = 412;
err.code = 'PreconditionFailed';
} else {
err = new Error('Unknow error, status: ' + result.status);
err.name = 'UnknowError';
if (result.status === -1 || result.status === -2) { //-1 is net error , -2 is timeout
err = new Error(result.message);
err.name = result.name;
err.status = result.status;
err.code = result.name;
} else {
// HEAD not exists resource
if (result.status === 404) {
err = new Error('Object not exists');
err.name = 'NoSuchKeyError';
err.status = 404;
err.code = 'NoSuchKey';
} else if (result.status === 412) {
err = new Error('Pre condition failed');
err.name = 'PreconditionFailedError';
err.status = 412;
err.code = 'PreconditionFailed';
} else {
err = new Error('Unknow error, status: ' + result.status);
err.name = 'UnknowError';
err.status = result.status;
}
err.requestId = result.headers['x-oss-request-id'];
err.host = '';
}
err.requestId = result.headers['x-oss-request-id'];
err.host = '';
} else {
var message = String(result.data);
debug('request response error data: %s', message);
Expand Down
6 changes: 4 additions & 2 deletions lib/browser/multipart.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
// check errors after all jobs are completed
for (var i = 0; i < results.length; i++) {
if (results[i].isError) {
throw new Error(
'Failed to upload some parts with error: ' + results[i].error.toString());
var error = results[i].error;
error.partNum = i;
error.message = 'Failed to upload some parts with error: ' + results[i].error.toString() + " part_num: "+ i;
throw error;
}
}
}
Expand Down
60 changes: 40 additions & 20 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,13 +305,26 @@ proto.createRequest = function createRequest(params) {

proto.request = function* request(params) {
var reqParams = this.createRequest(params);
var result = yield this.urllib.request(reqParams.url, reqParams.params);
debug('response %s %s, got %s, headers: %j', params.method, reqParams.url, result.status, result.headers);
if (params.successStatuses && params.successStatuses.indexOf(result.status) === -1) {
var err = yield* this.requestError(result);
var result;
var reqErr;
try {
result = yield this.urllib.request(reqParams.url, reqParams.params);
debug('response %s %s, got %s, headers: %j', params.method, reqParams.url, result.status, result.headers);
} catch (err) {
reqErr = err;
}
var err;
if (result && params.successStatuses && params.successStatuses.indexOf(result.status) === -1) {
err = yield this.requestError(result);
err.params = params;
} else if(reqErr) {
err = yield this.requestError(reqErr);
}

if (err) {
throw err;
}

if (params.xmlResponse) {
result.data = yield this.parseXML(result.data);
}
Expand Down Expand Up @@ -440,24 +453,31 @@ proto.parseXML = function parseXMLThunk(str) {
proto.requestError = function* requestError(result) {
var err;
if (!result.data || !result.data.length) {
// HEAD not exists resource
if (result.status === 404) {
err = new Error('Object not exists');
err.name = 'NoSuchKeyError';
err.status = 404;
err.code = 'NoSuchKey';
} else if (result.status === 412) {
err = new Error('Pre condition failed');
err.name = 'PreconditionFailedError';
err.status = 412;
err.code = 'PreconditionFailed';
} else {
err = new Error('Unknow error, status: ' + result.status);
err.name = 'UnknowError';
if (result.status === -1 || result.status === -2) { //-1 is net error , -2 is timeout
err = new Error(result.message);
err.name = result.name;
err.status = result.status;
err.code = result.name;
} else {
// HEAD not exists resource
if (result.status === 404) {
err = new Error('Object not exists');
err.name = 'NoSuchKeyError';
err.status = 404;
err.code = 'NoSuchKey';
} else if (result.status === 412) {
err = new Error('Pre condition failed');
err.name = 'PreconditionFailedError';
err.status = 412;
err.code = 'PreconditionFailed';
}else {
err = new Error('Unknow error, status: ' + result.status);
err.name = 'UnknowError';
err.status = result.status;
}
err.requestId = result.headers['x-oss-request-id'];
err.host = '';
}
err.requestId = result.headers['x-oss-request-id'];
err.host = '';
} else {
var message = String(result.data);
debug('request response error data: %s', message);
Expand Down
6 changes: 4 additions & 2 deletions lib/multipart.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,10 @@ proto._resumeMultipart = function* _resumeMultipart(checkpoint, options) {
// check errors after all jobs are completed
for (var i = 0; i < results.length; i++) {
if (results[i].isError) {
throw new Error(
'Failed to upload some parts with error: ' + results[i].error.toString());
var error = results[i].error;
error.partNum = i;
error.message = 'Failed to upload some parts with error: ' + results[i].error.toString() + " part_num: "+ i;
throw error;
}
}
}
Expand Down
19 changes: 18 additions & 1 deletion shims/xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ exports.requestWithCallback = function requestWithCallback(url, args, callback)
lookup: args.lookup,
};

if (args.timeout) {
options.timeout = args.timeout;
}

var sslNames = [
'pfx',
'key',
Expand Down Expand Up @@ -644,6 +648,18 @@ exports.requestWithCallback = function requestWithCallback(url, args, callback)
if (typeof(window) === 'undefined') {
// start connect timer just after `request` return, and just in nodejs environment
startConnectTimer();
} else {
req.on('timeout', function () {
if (statusCode === -1) {
statusCode = -2;
}
var msg = 'Connect timeout for ' + connectTimeout + 'ms';
var errorName = 'ConnectionTimeoutError';
__err = new Error(msg);
__err.name = errorName;
__err.requestId = reqId;
abortRequest();
});
}

function abortRequest() {
Expand Down Expand Up @@ -721,7 +737,8 @@ exports.requestWithCallback = function requestWithCallback(url, args, callback)
});

req.on('error', function (err) {
if (err.name === 'Error') {
//TypeError for browser fetch api, Error for browser xmlhttprequest api
if (err.name === 'Error' || err.name === 'TypeError') {
err.name = connected ? 'ResponseError' : 'RequestError';
}
err.message += ' (req "error")';
Expand Down
110 changes: 82 additions & 28 deletions test/browser.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -767,41 +767,43 @@ describe('browser', function () {
return function (done) {
assert.equal(true, res && Object.keys(res).length !== 0);
done();
}
};
}
}
);
assert.equal(true, result.res && Object.keys(result.res).length !== 0);
assert.equal(result.res.status, 200);
});

// it('should upload file using multipart upload with exception', function* () {
// // create a file with 1M random data
// var fileContent = Array(1024*1024).fill('a').join('')
// var file = new File([fileContent], 'multipart-upload-file');
//
// var name = prefix + 'multipart/upload-file-exception';
//
// var stubUploadPart = sinon.stub(this.store, '_uploadPart');
// stubUploadPart.throws("TestUploadPartException");
//
//
// var error_msg = "";
// try {
// yield this.store.multipartUpload(name, file, {
// progress: function () {
// return function (done) {
// done();
// };
// }
// });
// } catch (err) {
// error_msg = err.toString();
// }
// assert.equal(error_msg,
// "Error: Failed to upload some parts with error: TestUploadPartException");
// this.store._uploadPart().restore();
// });
it('should upload file using multipart upload with exception', function* () {
// create a file with 1M random data
var fileContent = Array(1024*1024).fill('a').join('')
var file = new File([fileContent], 'multipart-upload-file');

var name = prefix + 'multipart/upload-file-exception';

var stubUploadPart = sinon.stub(this.store, '_uploadPart');
stubUploadPart.throws("TestUploadPartException");

var error_msg = "";
var partNum;
try {
yield this.store.multipartUpload(name, file, {
progress: function () {
return function (done) {
done();
};
}
});
} catch (err) {
error_msg = err.message;
partNum = err.partNum;
}
assert.equal(error_msg,
"Failed to upload some parts with error: TestUploadPartException part_num: 0");
assert.equal(partNum, 0);
this.store._uploadPart.restore();
});
});
});

Expand Down Expand Up @@ -835,4 +837,56 @@ describe('browser', function () {
timemachine.reset();
})
});

describe('request err', function() {
before(function* () {
var ossConfig = {
region: stsConfig.region,
accessKeyId: stsConfig.Credentials.AccessKeyId,
accessKeySecret: stsConfig.Credentials.AccessKeySecret,
stsToken: stsConfig.Credentials.SecurityToken,
bucket: stsConfig.bucket,
timeout: 1
};
this.store = oss(ossConfig);
});
it('request timeout exception', function* () {
var fileContent = Array(1024*1024).fill('a').join('')
var file = new File([fileContent], 'multipart-upload-file');

var name = prefix + 'multipart/upload-file-timeout';

var timeout_err = "";
try {
yield this.store.multipartUpload(name, file);
} catch (err) {
timeout_err = err;
}
assert.equal(true, timeout_err && Object.keys(timeout_err).length !== 0);
assert.equal(timeout_err.status, -2);
});

it('request net exception', function* () {
var fileContent = Array(1024*1024).fill('a').join('')
var file = new File([fileContent], 'multipart-upload-file');

var name = prefix + 'multipart/upload-file-timeout';
var stubNetError = sinon.stub(this.store.urllib, 'request');
var netErr = new Error('TestNetErrorException');
netErr.status = -1;
netErr.code = 'RequestError';
netErr.name = 'RequestError';
stubNetError.throws(netErr);
var net_err = "";
try {
yield this.store.multipartUpload(name, file);
} catch (err) {
net_err = err;
}
assert.equal(true, net_err && Object.keys(net_err).length !== 0);
assert.equal(net_err.status, -1);

this.store.urllib.request.restore();
});
});
});
Loading

0 comments on commit 2021661

Please sign in to comment.