mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-06-09 20:16:48 +08:00
feat($http): add xhr statusText to completeRequest callback
Makes xhr status text accessible is $http success/error callback. See www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-statustext Closes #2335 Closes #2665 Closes #6713
This commit is contained in:
committed by
Caitlin Potter
parent
9f62d9d20b
commit
1d2414ca93
@@ -571,6 +571,7 @@ function $HttpProvider() {
|
||||
* - **status** – `{number}` – HTTP status code of the response.
|
||||
* - **headers** – `{function([headerName])}` – Header getter function.
|
||||
* - **config** – `{Object}` – The configuration object that was used to generate the request.
|
||||
* - **statusText** – `{string}` – HTTP status text of the response.
|
||||
*
|
||||
* @property {Array.<Object>} pendingRequests Array of config objects for currently pending
|
||||
* requests. This is primarily meant to be used for debugging purposes.
|
||||
@@ -945,9 +946,9 @@ function $HttpProvider() {
|
||||
} else {
|
||||
// serving from cache
|
||||
if (isArray(cachedResp)) {
|
||||
resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
|
||||
resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]), cachedResp[3]);
|
||||
} else {
|
||||
resolvePromise(cachedResp, 200, {});
|
||||
resolvePromise(cachedResp, 200, {}, 'OK');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -971,17 +972,17 @@ function $HttpProvider() {
|
||||
* - resolves the raw $http promise
|
||||
* - calls $apply
|
||||
*/
|
||||
function done(status, response, headersString) {
|
||||
function done(status, response, headersString, statusText) {
|
||||
if (cache) {
|
||||
if (isSuccess(status)) {
|
||||
cache.put(url, [status, response, parseHeaders(headersString)]);
|
||||
cache.put(url, [status, response, parseHeaders(headersString), statusText]);
|
||||
} else {
|
||||
// remove promise from the cache
|
||||
cache.remove(url);
|
||||
}
|
||||
}
|
||||
|
||||
resolvePromise(response, status, headersString);
|
||||
resolvePromise(response, status, headersString, statusText);
|
||||
if (!$rootScope.$$phase) $rootScope.$apply();
|
||||
}
|
||||
|
||||
@@ -989,7 +990,7 @@ function $HttpProvider() {
|
||||
/**
|
||||
* Resolves the raw $http promise.
|
||||
*/
|
||||
function resolvePromise(response, status, headers) {
|
||||
function resolvePromise(response, status, headers, statusText) {
|
||||
// normalize internal statuses to 0
|
||||
status = Math.max(status, 0);
|
||||
|
||||
@@ -997,7 +998,8 @@ function $HttpProvider() {
|
||||
data: response,
|
||||
status: status,
|
||||
headers: headersGetter(headers),
|
||||
config: config
|
||||
config: config,
|
||||
statusText : statusText
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,8 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
||||
completeRequest(callback,
|
||||
status || xhr.status,
|
||||
response,
|
||||
responseHeaders);
|
||||
responseHeaders,
|
||||
xhr.statusText || '');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -135,7 +136,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
||||
xhr && xhr.abort();
|
||||
}
|
||||
|
||||
function completeRequest(callback, status, response, headersString) {
|
||||
function completeRequest(callback, status, response, headersString, statusText) {
|
||||
// cancel timeout and subsequent timeout promise resolution
|
||||
timeoutId && $browserDefer.cancel(timeoutId);
|
||||
jsonpDone = xhr = null;
|
||||
@@ -148,9 +149,10 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
||||
}
|
||||
|
||||
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
|
||||
status = status == 1223 ? 204 : status;
|
||||
status = status === 1223 ? 204 : status;
|
||||
statusText = statusText || '';
|
||||
|
||||
callback(status, response, headersString);
|
||||
callback(status, response, headersString, statusText);
|
||||
$browser.$$completeOutstandingRequest(noop);
|
||||
}
|
||||
};
|
||||
|
||||
46
src/ngMock/angular-mocks.js
vendored
46
src/ngMock/angular-mocks.js
vendored
@@ -1090,12 +1090,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
||||
responsesPush = angular.bind(responses, responses.push),
|
||||
copy = angular.copy;
|
||||
|
||||
function createResponse(status, data, headers) {
|
||||
function createResponse(status, data, headers, statusText) {
|
||||
if (angular.isFunction(status)) return status;
|
||||
|
||||
return function() {
|
||||
return angular.isNumber(status)
|
||||
? [status, data, headers]
|
||||
? [status, data, headers, statusText]
|
||||
: [200, status, data];
|
||||
};
|
||||
}
|
||||
@@ -1120,7 +1120,8 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
||||
function handleResponse() {
|
||||
var response = wrapped.response(method, url, data, headers);
|
||||
xhr.$$respHeaders = response[2];
|
||||
callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders());
|
||||
callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
|
||||
copy(response[3] || ''));
|
||||
}
|
||||
|
||||
function handleTimeout() {
|
||||
@@ -1188,16 +1189,17 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
||||
* request is handled.
|
||||
*
|
||||
* - respond –
|
||||
* `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
|
||||
* – The respond method takes a set of static data to be returned or a function that can return
|
||||
* an array containing response status (number), response data (string) and response headers
|
||||
* (Object).
|
||||
* `{function([status,] data[, headers, statusText])
|
||||
* | function(function(method, url, data, headers)}`
|
||||
* – The respond method takes a set of static data to be returned or a function that can
|
||||
* return an array containing response status (number), response data (string), response
|
||||
* headers (Object), and the text for the status (string).
|
||||
*/
|
||||
$httpBackend.when = function(method, url, data, headers) {
|
||||
var definition = new MockHttpExpectation(method, url, data, headers),
|
||||
chain = {
|
||||
respond: function(status, data, headers) {
|
||||
definition.response = createResponse(status, data, headers);
|
||||
respond: function(status, data, headers, statusText) {
|
||||
definition.response = createResponse(status, data, headers, statusText);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1312,17 +1314,18 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
|
||||
* request is handled.
|
||||
*
|
||||
* - respond –
|
||||
* `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
|
||||
* – The respond method takes a set of static data to be returned or a function that can return
|
||||
* an array containing response status (number), response data (string) and response headers
|
||||
* (Object).
|
||||
* `{function([status,] data[, headers, statusText])
|
||||
* | function(function(method, url, data, headers)}`
|
||||
* – The respond method takes a set of static data to be returned or a function that can
|
||||
* return an array containing response status (number), response data (string), response
|
||||
* headers (Object), and the text for the status (string).
|
||||
*/
|
||||
$httpBackend.expect = function(method, url, data, headers) {
|
||||
var expectation = new MockHttpExpectation(method, url, data, headers);
|
||||
expectations.push(expectation);
|
||||
return {
|
||||
respond: function(status, data, headers) {
|
||||
expectation.response = createResponse(status, data, headers);
|
||||
respond: function (status, data, headers, statusText) {
|
||||
expectation.response = createResponse(status, data, headers, statusText);
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1833,13 +1836,14 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
|
||||
* control how a matched request is handled.
|
||||
*
|
||||
* - respond –
|
||||
* `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
|
||||
* `{function([status,] data[, headers, statusText])
|
||||
* | function(function(method, url, data, headers)}`
|
||||
* – The respond method takes a set of static data to be returned or a function that can return
|
||||
* an array containing response status (number), response data (string) and response headers
|
||||
* (Object).
|
||||
* - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
|
||||
* handler will be passed through to the real backend (an XHR request will be made to the
|
||||
* server.)
|
||||
* an array containing response status (number), response data (string), response headers
|
||||
* (Object), and the text for the status (string).
|
||||
* - passThrough – `{function()}` – Any request matching a backend definition with
|
||||
* `passThrough` handler will be passed through to the real backend (an XHR request will be made
|
||||
* to the server.)
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -76,6 +76,32 @@ describe('$httpBackend', function() {
|
||||
expect(xhr.$$data).toBe(null);
|
||||
});
|
||||
|
||||
it('should call completion function with xhr.statusText if present', function() {
|
||||
callback.andCallFake(function(status, response, headers, statusText) {
|
||||
expect(statusText).toBe('OK');
|
||||
});
|
||||
|
||||
$backend('GET', '/some-url', null, callback);
|
||||
xhr = MockXhr.$$lastInstance;
|
||||
xhr.statusText = 'OK';
|
||||
xhr.readyState = 4;
|
||||
xhr.onreadystatechange();
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('should call completion function with empty string if not present', function() {
|
||||
callback.andCallFake(function(status, response, headers, statusText) {
|
||||
expect(statusText).toBe('');
|
||||
});
|
||||
|
||||
$backend('GET', '/some-url', null, callback);
|
||||
xhr = MockXhr.$$lastInstance;
|
||||
xhr.readyState = 4;
|
||||
xhr.onreadystatechange();
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
|
||||
it('should normalize IE\'s 1223 status code into 204', function() {
|
||||
callback.andCallFake(function(status) {
|
||||
expect(status).toBe(204);
|
||||
|
||||
@@ -481,6 +481,30 @@ describe('$http', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should pass statusText in response object when a request is successful', function() {
|
||||
$httpBackend.expect('GET', '/url').respond(200, 'SUCCESS', {}, 'OK');
|
||||
$http({url: '/url', method: 'GET'}).then(function(response) {
|
||||
expect(response.statusText).toBe('OK');
|
||||
callback();
|
||||
});
|
||||
|
||||
$httpBackend.flush();
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
|
||||
it('should pass statusText in response object when a request fails', function() {
|
||||
$httpBackend.expect('GET', '/url').respond(404, 'ERROR', {}, 'Not Found');
|
||||
$http({url: '/url', method: 'GET'}).then(null, function(response) {
|
||||
expect(response.statusText).toBe('Not Found');
|
||||
callback();
|
||||
});
|
||||
|
||||
$httpBackend.flush();
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
|
||||
it('should pass in the response object when a request failed', function() {
|
||||
$httpBackend.expect('GET', '/url').respond(543, 'bad error', {'request-id': '123'});
|
||||
$http({url: '/url', method: 'GET'}).then(null, function(response) {
|
||||
|
||||
20
test/ngMock/angular-mocksSpec.js
vendored
20
test/ngMock/angular-mocksSpec.js
vendored
@@ -1068,29 +1068,29 @@ describe('ngMock', function() {
|
||||
hb.flush();
|
||||
|
||||
expect(callback.callCount).toBe(2);
|
||||
expect(callback.argsForCall[0]).toEqual([201, 'second', '']);
|
||||
expect(callback.argsForCall[1]).toEqual([200, 'first', '']);
|
||||
expect(callback.argsForCall[0]).toEqual([201, 'second', '', '']);
|
||||
expect(callback.argsForCall[1]).toEqual([200, 'first', '', '']);
|
||||
});
|
||||
|
||||
|
||||
describe('respond()', function() {
|
||||
it('should take values', function() {
|
||||
hb.expect('GET', '/url1').respond(200, 'first', {'header': 'val'});
|
||||
hb.expect('GET', '/url1').respond(200, 'first', {'header': 'val'}, 'OK');
|
||||
hb('GET', '/url1', undefined, callback);
|
||||
hb.flush();
|
||||
|
||||
expect(callback).toHaveBeenCalledOnceWith(200, 'first', 'header: val');
|
||||
expect(callback).toHaveBeenCalledOnceWith(200, 'first', 'header: val', 'OK');
|
||||
});
|
||||
|
||||
it('should take function', function() {
|
||||
hb.expect('GET', '/some').respond(function(m, u, d, h) {
|
||||
return [301, m + u + ';' + d + ';a=' + h.a, {'Connection': 'keep-alive'}];
|
||||
hb.expect('GET', '/some').respond(function (m, u, d, h) {
|
||||
return [301, m + u + ';' + d + ';a=' + h.a, {'Connection': 'keep-alive'}, 'Moved Permanently'];
|
||||
});
|
||||
|
||||
hb('GET', '/some', 'data', callback, {a: 'b'});
|
||||
hb.flush();
|
||||
|
||||
expect(callback).toHaveBeenCalledOnceWith(301, 'GET/some;data;a=b', 'Connection: keep-alive');
|
||||
expect(callback).toHaveBeenCalledOnceWith(301, 'GET/some;data;a=b', 'Connection: keep-alive', 'Moved Permanently');
|
||||
});
|
||||
|
||||
it('should default status code to 200', function() {
|
||||
@@ -1119,8 +1119,8 @@ describe('ngMock', function() {
|
||||
hb.flush();
|
||||
|
||||
expect(callback.callCount).toBe(2);
|
||||
expect(callback.argsForCall[0]).toEqual([200, 'first', '']);
|
||||
expect(callback.argsForCall[1]).toEqual([200, 'second', '']);
|
||||
expect(callback.argsForCall[0]).toEqual([200, 'first', '', '']);
|
||||
expect(callback.argsForCall[1]).toEqual([200, 'second', '', '']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1415,7 +1415,7 @@ describe('ngMock', function() {
|
||||
hb[shortcut]('/foo').respond('bar');
|
||||
hb(method, '/foo', undefined, callback);
|
||||
hb.flush();
|
||||
expect(callback).toHaveBeenCalledOnceWith(200, 'bar', '');
|
||||
expect(callback).toHaveBeenCalledOnceWith(200, 'bar', '', '');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user