I've got working backend in Spring Boot with JWT-secured endpoint for modifying avatar of current user. The following request from Insomnia with correct Bearer works fine:
But this code
updateAvatar(context, avatar) {
const fd = new FormData();
fd.append('file', avatar.data);
return new Promise((resolve, reject) => {
axios.post('/saveavatar',
{file: fd},
{headers: {'Authorization': 'Bearer ' + localStorage.getItem('access_token')}})
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
},
fails with error
the request was rejected because no multipart boundary was found
What am I doing wrong?
The second argument to post should be the actual FormData, fd in your case.
axios.post('/saveavatar',
fd,
{headers: {'Authorization': 'Bearer ' + localStorage.getItem('access_token')}})
The reason it works in Insomia is that it takes care of your request and figures out that it needs to ads a boundary, axios will do the same, but needs a valid FormData.
Related
I'm trying to fetch an image resource that's part of a conversation message.
I've tried both FETCH as well as using AXIOS but I'm getting the same error message.
Here's an example of my FETCH request
const token = `${accountSid}:${authToken}`;
const encodedToken = Buffer.from(token).toString('base64');
let response = await fetch('https://mcs.us1.twilio.com/v1/Services/<SERVICE_SID>/Media/<MEDIA_SID>',
{
method:'GET',
headers: {
'Authorization': `Basic ${encodedToken}`,
}
});
let data = await response.json();
console.log(data);
And here's what Axios looked like
let config = {
method: 'get',
crossdomain: true,
url: 'https://mcs.us1.twilio.com/v1/Services/<SERVICE_SID>/Media/<MEDIA_SID>',
headers: {
'Authorization': `Basic ${encodedToken}`,
},
};
try {
const media = await axios(config);
console.dir(media);
} catch(err) {
console.error(err);
}
Both ways are NOT working.
After looking into it more, I found out that Chrome makes a pre-flight request and as part of that requests the allowed headers from the server.
The response that came back was this
as you can see, in the "Response Headers" I don't see the Access-Control-Allow-Headers which should have been set to Authorization
What am I missing here?
I have made sure that my id/password as well as the URL i'm using are fine. In fact, I've ran this request through POSTMAN on my local machine and that returned the results just fine. The issue is ONLY happening when I do it in my code and run it in the browser.
I figured it out.
I don't have to make an http call to get the URL. It can be retrieved by simply
media.getContentTemporaryUrl();
I am trying to understand this code. And also how to use it
https://stackoverflow.com/a/53294310/2897115
createAxiosResponseInterceptor() {
const interceptor = axios.interceptors.response.use(
response => response,
error => {
// Reject promise if usual error
if (errorResponse.status !== 401) {
return Promise.reject(error);
}
/*
* When response code is 401, try to refresh the token.
* Eject the interceptor so it doesn't loop in case
* token refresh causes the 401 response
*/
axios.interceptors.response.eject(interceptor); <---- What does this do
return axios.post('/api/refresh_token', {
'refresh_token': this._getToken('refresh_token')
}).then(response => {
saveToken();
error.response.config.headers['Authorization'] = 'Bearer ' + response.data.access_token;
return axios(error.response.config); <--- what does this do
}).catch(error => {
destroyToken();
this.router.push('/login');
return Promise.reject(error);
}).finally(createAxiosResponseInterceptor);
}
);
}
Generally i use axios script with access_token is as:
const url = "dj-rest-auth/password/change/";
const auth = {
headers: {
Authorization: "Bearer " + localStorage.getItem("access_token"),
Accept: "application/json",
"Content-Type": "application/json",
},
};
const data = {
old_password: old_password,
new_password1: new_password1,
new_password2: new_password2,
};
const promise = axios.post(url, data, auth);
promise
.then((res) => {
console.log(res)
})
.catch((err) => {
if (err.response) {
console.log(`${err.response.status} :: ${err.response.statusText}`)
console.log(err.response.data)
}
})
And in this code how to use the interceptor
Eject interceptor
axios.interceptors.response.eject(interceptor); <---- What does this do
Internally, interceptors.response is an array of interceptors, the method axios.interceptors.response.use return the id of the new interceptor. Calling eject passing the id of the interceptor will set the corresponding item in the array to null, and the interceptor has no effect anymore.
When we receive the response code 401, we use the interceptor to send another request to get the token. To avoid the infinity loop if the latter also receives the response code 401, we eject the interceptor in this case.
Resend original request
return axios(error.response.config); <--- what does this do
After receiving the token, we want to resend the original request, its configuration is stored in error.response.config according to the response schema
To use the function, call it before sending the request. (People talk about it in the thread of the accepted answer.)
I'm working with React and axios. I'm trying to fetch the response using axios however, unable to understand why I'm getting wrong content-type even though I'm setting it in my backend code.
Code (backend):
router.get(url, async (req, res) => {
// return new Promise(async (resolve, reject) => {
try {
if (file exists) {
var fileContents = Buffer.from(document[0].data, "base64"); //document contains the data from the postgres database
var readStream = new stream.PassThrough();
readStream.end(fileContents);
res.set(
"Content-disposition",
"attachment; filename=" + document[0].fileName
);
res.setHeader("content-type", document[0].fileType);
readStream.pipe(res);
console.log("+++++++++++++++++++");
console.log(res);
console.log("+++++++++++++++++++");
return;
} else {
res.json({
status: 0,
message: "File not found",
});
return;
}
// resolve({ document });
} catch (err) {
console.log(err);
}
});
The above backend code works absolutely fine. I even printed the response to check whether the content-type is setting or not. I'm even providing the output snippet for that as well
However, in the frontend if I try to fetch the response this is what I'm receiving
I'm not sure what's wrong. Why I'm receiving wrong content-type. Even the content length is same for any sort of file which I try to download.
The axios call :
let response = await Axios.get(fileURL, {
responseType: "blob"/"arraybuffer",
Authorization: "Bearer " + token,
});
Response.data output :
Any help will be appreciated!
I'm currently building out an Angular 7 App, and trying to implement the following HTTP API Call Scenario:
Request for an Application Token:
https://(URL)/token
Request Type: POST
Headers:
Accept: application/json
Request Body: empty
I have a Service class in the Angular app and the code is as follows:
import { HttpClient } from '#angular/common/http';
import { HttpHeaders } from '#angular/common/http';
The requestToken function is implemented as follows:
requestToken() {
let headers = new HttpHeaders();
headers = headers.set('Accept', 'application/json');
return this.http.post(this.configUrl + '/token', headers);
}
The Service is then called in one of the components in the App:-
getToken() {
this.service.requestToken().subscribe( res => {
console.log(res);
}, error => {
console.log(error);
});
}
When I run the App, I get a 404 Not Found error in the console. I used Postman to make an API call, setting the 'Accept' header to 'application/json' and then specifying url as https://(URL)/token and I successfully get a response. But I'm unable to make it work via Angular.
Is there something else I need to do to set the header properly in Angular? Also, I have no way to check if CORS has been enabled on the API server as this is a third-party service which I'm trying to call.
Any help would be appreciated. Thanks
Solved the problem. Changed the POST call to the following:
requestToken() {
const httpHeaders = new HttpHeaders({
'Accept': 'application/json'
});
return this.http.post(this.configUrl + '/token', { body: ''}, { headers: httpHeaders });
}
Had to add an empty 'body' parameter
I need to delete a record on my mongodb using mongoose.
Here is my component
deleteProduct(product){
this._confirmationService.confirm({
message: 'Are you sure you want to delete the item?',
accept: () => {
this._productsAdminService.deleteProduct(product._id)
.subscribe(products => {
products.forEach(function(product){
if(product.cat_id === 1) product.catName = 'Dota Shirts';
if(product.cat_id === 2) product.catName = 'Gym Shirts';
if(product.cat_id === 3) product.catName = 'Car Shirts';
});
this.products = products;
},
err => console.log(err));
}
})
}
basically this will just pass the product id to the service to execute http request.
Here is my service
deleteProduct(productId){
let headers = new Headers({'Authorization': 'JWT ' + localStorage.getItem('currentUserToken')});
let options = new RequestOptions({ headers: headers});
return this._http.delete('http://localhost:3000/admin/products/delete/' + productId, options)
.map((response: Response) => response.json())
.catch(this._handlerError);
}
I am using the delete method to call my API in expressJS.
Here is my API
productsAdminRouter.route('/delete/:productId')
.delete(function(req,res){
id = req.params.productId;
console.log(id);
Products.findByIdAndRemove(id)
.exec(function(err, done){
if (err) throw err;
Products.find()
.exec(function(err, products){
res.json(products);
});
});
});
But I always got this error
Can anyone help? I'm stuck.
Exactly like #flashjpr said
I had to write an especific middleware to my entity "ticket".
var allowDelete = function(req, res, next){
res.append('Access-Control-Allow-Methods', 'DELETE')
next()
}
and pass it to the first middleware of that entity
app.use('/tickets', allowDelete, tickets);
EDIT: I'm was using expressjs.
I had the same problem the other day when working with a Java-Spring backend: when Cross-origin resource sharing (or simply cors) is happening, Angular sends apre-flight request before the actual (here DELETE) request which is of type OPTIONS(http).
What you have to do is:
enable CORS on your server
make sure your server accepts OPTIONS request on that particular endpoint ( /delete/:productId)
add the Access-Control-Allow-Methods header to the response of the OPTIONS, DELETE