I have an Angular 1.x application that is expecting to receive a binary file download (pdf) using a $http.post()
call. The problem is, I'd like to alternatively get a processing error message that's sent as json. I can do this with the config
headers: {
'Accept': 'application/pdf, application/json'
}
The problem is I have have to set responseType: 'arraybuffer'
, otherwise the pdf binary is escaped (or altered such that it doesn't load). However, that prevents the json from being read or interpreted correctly.
How can I have both?
Edit: I'm going to try to clarify; perhaps my understanding is incorrect.
$http({
method: 'POST',
url: "/myresource",
headers: {
'Accept': 'application/pdf, application/json'
},
responseType: 'arraybuffer'
})
.then(
function(response) {
// handle pdf download via `new Blob([data])`
}, function(response) {
// pop up a message based on response.data
}
)
In a scenario where I return a pdf data block and a http status of 200, the first function handles the response and prompts the user to save the file. However if the status is an error (422), the response.data
is undefined. I assume this is because the responseType
is preventing the json from being handled correctly.
If I remove the responseType
line, the error data is correctly read, but when the pdf is saved, some of the file bytes aren't correct and it's effectively corrupted. I assume this is because the file is being encoded because javascript was expecting a string.
To add or overwrite these defaults, simply add or remove a property from these configuration objects. To add headers for an HTTP method other than POST or PUT, simply add a new object with the lowercased HTTP method name as the key, e.g. $httpProvider. defaults.
$http is an AngularJS service for reading data from remote servers.
This interceptor is called when the $http receives the response from the server. This function receives a response object as a parameter return a response object or a promise. A response interceptor is used to modify the response data or adding a new set of values, calling another module or services call.
In the Angular client code when calling delete method you should set {responseType: ‘text’} so that it constructs a DELETE request that interprets the body as a text string and returns a string. For full Angular code please refer this post- Angular HttpClient to Communicate With Backend Service
As you can see method returns a String "Successfully deleted" if deletion is successful otherwise it returns "Error while deleting". In the Angular client code when calling delete method you should set {responseType: ‘text’} so that it constructs a DELETE request that interprets the body as a text string and returns a string.
Actually, responseType only allows 'json' value. Typescript knows that. So writing 'text' as 'json' means "I give you 'text' value, but for type-checking, consider I gave you 'json'". So typescript won't complain. This only allows you to "lie" to typescript.
The error appears because the post method signature does not contain a generic type argument when responseType: 'text. post<T> (url: string, body: any | null, options?: { ... responseType?: 'json'; ... }): Observable<T>;
An XHR responseType
property can not be changed after a response has been loaded. But an arraybuffer
can be decoded and parsed depending on Content-Type
:
var config = {
responseType: "arraybuffer",
transformResponse: jsonBufferToObject,
};
function jsonBufferToObject (data, headersGetter, status) {
var type = headersGetter("Content-Type");
if (!type.startsWith("application/json")) {
return data;
};
var decoder = new TextDecoder("utf-8");
var domString = decoder.decode(data);
var json = JSON.parse(domString);
return json;
};
$http.get(url, config);
The above example sets the XHR to return an arraybuffer
and uses a transformResponse
function to detect Content-Type: application/json
and convert it if necessary.
The DEMO on PLNKR
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With