Bring some sanity to request parsing and error handling (#2335)
* Update docs/request.md * Bring some sanity to request parsing and error handling - The browser can do JSON parsing itself. Let's defer to that where possible. (A few IE hacks are required here, though.) - Don't propagate any error that occurs before `deserialize`/`extract`. - Allow sending raw array buffers/blobs/etc. to `deserialize`. - Align behavior more closely with the XHR spec. - Send the more useful parsed response to `deserialize`, not the less useful string response.
This commit is contained in:
parent
09afc54c7b
commit
794e8e963f
5 changed files with 55 additions and 18 deletions
|
|
@ -79,7 +79,7 @@ module.exports = function($window, Promise) {
|
|||
}
|
||||
if (args.withCredentials) xhr.withCredentials = args.withCredentials
|
||||
if (args.timeout) xhr.timeout = args.timeout
|
||||
if (args.responseType) xhr.responseType = args.responseType
|
||||
xhr.responseType = args.responseType || (typeof args.extract === "function" ? "" : "json")
|
||||
|
||||
for (var key in args.headers) {
|
||||
if ({}.hasOwnProperty.call(args.headers, key)) {
|
||||
|
|
@ -96,19 +96,38 @@ module.exports = function($window, Promise) {
|
|||
if (xhr.readyState === 4) {
|
||||
try {
|
||||
var success = (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || (/^file:\/\//i).test(url)
|
||||
var response = xhr.responseText
|
||||
// When the response type isn't "" or "text",
|
||||
// `xhr.responseText` is the wrong thing to use.
|
||||
// Browsers do the right thing and throw here, and we
|
||||
// should honor that and do the right thing by
|
||||
// preferring `xhr.response` where possible/practical.
|
||||
var response = xhr.response, message
|
||||
|
||||
if (response == null) {
|
||||
try {
|
||||
response = xhr.responseText
|
||||
// Note: this snippet is intentionally *after*
|
||||
// `xhr.responseText` is accessed, since the
|
||||
// above will throw in modern browsers (thus
|
||||
// skipping the rest of this section). It's an
|
||||
// IE hack to detect and work around the lack of
|
||||
// native `responseType: "json"` support there.
|
||||
if (typeof args.extract !== "function" && xhr.responseType === "json") response = JSON.parse(response)
|
||||
}
|
||||
catch (e) { response = null }
|
||||
}
|
||||
|
||||
if (typeof args.extract === "function") {
|
||||
response = args.extract(xhr, args)
|
||||
success = true
|
||||
} else if (typeof args.deserialize === "function") {
|
||||
response = args.deserialize(response)
|
||||
} else {
|
||||
try {response = response ? JSON.parse(response) : null}
|
||||
catch (e) {throw new Error("Invalid JSON: " + response)}
|
||||
}
|
||||
if (success) resolve(response)
|
||||
else {
|
||||
var error = new Error(xhr.responseText)
|
||||
try { message = xhr.responseText }
|
||||
catch (e) { message = response }
|
||||
var error = new Error(message)
|
||||
error.code = xhr.status
|
||||
error.response = response
|
||||
reject(error)
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ o.spec("xhr", function() {
|
|||
}
|
||||
})
|
||||
xhr({method: "GET", url: "/item", deserialize: deserialize}).then(function(data) {
|
||||
o(data).equals("{\"test\":123}")
|
||||
o(data).deepEquals({test: 123})
|
||||
}).then(done)
|
||||
})
|
||||
o("deserialize parameter works in POST", function(done) {
|
||||
|
|
@ -304,12 +304,12 @@ o.spec("xhr", function() {
|
|||
}
|
||||
})
|
||||
xhr({method: "POST", url: "/item", deserialize: deserialize}).then(function(data) {
|
||||
o(data).equals("{\"test\":123}")
|
||||
o(data).deepEquals({test: 123})
|
||||
}).then(done)
|
||||
})
|
||||
o("extract parameter works in GET", function(done) {
|
||||
var extract = function() {
|
||||
return JSON.stringify({test: 123})
|
||||
return {test: 123}
|
||||
}
|
||||
|
||||
mock.$defineRoutes({
|
||||
|
|
@ -318,12 +318,12 @@ o.spec("xhr", function() {
|
|||
}
|
||||
})
|
||||
xhr({method: "GET", url: "/item", extract: extract}).then(function(data) {
|
||||
o(data).equals("{\"test\":123}")
|
||||
o(data).deepEquals({test: 123})
|
||||
}).then(done)
|
||||
})
|
||||
o("extract parameter works in POST", function(done) {
|
||||
var extract = function() {
|
||||
return JSON.stringify({test: 123})
|
||||
return {test: 123}
|
||||
}
|
||||
|
||||
mock.$defineRoutes({
|
||||
|
|
@ -332,7 +332,7 @@ o.spec("xhr", function() {
|
|||
}
|
||||
})
|
||||
xhr({method: "POST", url: "/item", extract: extract}).then(function(data) {
|
||||
o(data).equals("{\"test\":123}")
|
||||
o(data).deepEquals({test: 123})
|
||||
}).then(done)
|
||||
})
|
||||
o("ignores deserialize if extract is defined", function(done) {
|
||||
|
|
@ -545,7 +545,8 @@ o.spec("xhr", function() {
|
|||
})
|
||||
xhr({method: "GET", url: "/item"}).catch(function(e) {
|
||||
o(e instanceof Error).equals(true)
|
||||
o(e.message).equals(JSON.stringify({error: "error"}))
|
||||
o(e.message).equals("[object Object]")
|
||||
o(e.response).deepEquals({error: "error"})
|
||||
o(e.code).equals(500)
|
||||
}).then(done)
|
||||
})
|
||||
|
|
@ -568,7 +569,8 @@ o.spec("xhr", function() {
|
|||
}
|
||||
})
|
||||
xhr({method: "GET", url: "/item"}).catch(function(e) {
|
||||
o(e.message).equals("Invalid JSON: error")
|
||||
o(e.message).equals("null")
|
||||
o(e.response).equals(null)
|
||||
}).then(done)
|
||||
})
|
||||
o("triggers all branched catches upon rejection", function(done) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue