Possible bug with axios default headers and transformRequest - reactjs

This bug has caused serious trouble for me. Finally i was able to get to the root of it.
(A similar version of bug has been reported in GitHub but it has been marked as fixed)
Axios will fail to set the correct header type and goes for default header type when transformRequest is used.
I am not sure what exactly is causing this issue but here is a quick way of reproducing the issue.
Here i have defined an axiosInstance
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 360000,
transformRequest: [
function (data, headers) {
const accessToken = window.localStorage.getItem('access_token');
if (accessToken) {
headers['Authorization'] = `Bearer ${accessToken}`;
} else {
delete headers.Authorization;
}
return JSON.stringify(data);
},
],
headers: {
'Content-Type': 'application/json',
accept: 'application/json',
Authorization: `Bearer ${window.localStorage.getItem('access_token')}`,
},
});
Now i have to send multipart/form-data.
let formData = new FormData();
formData.append('profile_pic', file, file.name);
axiosInstance
.put('http://127.0.0.1:8000/users/profile-pic-upload/', formData)
.then((res) => console.log(res))
.catch((err) => alert(err));
Since formData is contains image here i expected the axios to override the default header's content-type from 'application/json' to 'multipart/form-data'. But it turns out the content-type in the sent request packet is still 'application/json'.
But when i comment out the transformRequest section. Surprisingly it correctly sets the content-type to 'multipart/form-data'.
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 360000,
transformRequest: [
// function (data, headers) {
// const accessToken = window.localStorage.getItem('access_token');
// if (accessToken) {
// headers['Authorization'] = `Bearer ${accessToken}`;
// } else {
// delete headers.Authorization;
// }
// return JSON.stringify(data);
// },
],
headers: {
'Content-Type': 'application/json',
accept: 'application/json',
Authorization: `Bearer ${window.localStorage.getItem('access_token')}`,
},
});
I am using axios 0.20 (i noted that axios 0.21 also has same issue as well).
I found a similar issue on Github it says it has been fixed in axios 0.20
https://github.com/axios/axios/issues/2623
Please confirm that whether this is an existing bug or am i doing something wrong.
I have written more detailed description in my previous stackoverflow post.
AxiosInstance setting default type to "application/x-www-form-urlencoded" instead of expected "multipart/form-data"

Related

Bearer token not showing up in the request headers when trying to hit the API from react application

This is my POST service -
export const Services = {
post: (url: string, body: IKeyValuePairs<any>= {}, headers: IKeyValuePairs<string> = {}): AxiosPromise => {
return axios.post(url, body, headers);
},
}
And I am using this service like below -
const response = await Services.post(`${Configuration.Instance.BaseUrl}/roles`, { roleName, description, permission }, contentTypeHeader);
Using contentTypeHeader as
const token = localStorage.getItem('accessToken');
const contentTypeHeader = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
};
Somoehow on the browser, in chrome, no authorization is showing up -
Anyone any idea what I am missing ?
Axios is expecting headers in the following format:
const contentTypeHeader = {
'Headers': {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
};

Saving set-cookie value to browser cookies in React

I get this cookie value from the server and I want to save this to my browser.
Set-Cookie: succeeedd=noooo!; Path=/
I've tried with
const res = yield axios.post(`${config.authURL}/login`, data, {
headers: {
'Content-Type': 'application/json',
Cookie: 'cookie1=value',
},
});
and
const res = yield axios.post(
`${config.authURL}/login`,
data,
{
headers: {
'Content-Type': 'application/json',
},
},
{ withCredentials: true })
Both are not saving cookies into the browser cookies. How can I save Set-Cookie value to the browser so I can use them for authentication?
Pass withCredentials: true as below
const res = yield axios.post(
`${config.authURL}/login`,
data,
{
headers: { 'Content-Type': 'application/json' },
withCredentials: true
}
);
For more generic configuration,
// You can add it in a separate config file
const request = axios.create({ withCredentials: true });
// While making API call
request.post(`${config.authURL}/login`, data, { headers: {...} });
Check here for more details.
install universal-cookie with npm
import Cookies from 'universal-cookie';
const cookies = new Cookies();
axios.post(URL, data, {
headers: {
'Content-Type': 'application/json',
},
{ withCredentials: true }
})
.then((res) => {
let name = res.data.blobName;
let value = res.data.blobValue;
cookies.set(`${name}`, `${value}`);
})
.catch(function (error) {
console.log(error);
});

Redux axios problem by setting `Content-Type: application/x-www-form-urlencoded`

I implemented a redux action using axios middleware. Unfortunately the API endpoint accepts form data only, so I had to set it like this.
const saveQuery = (title, description) => {
const bodyFormData = new FormData();
bodyFormData.set('title', title);
bodyFormData.set('description', description);
return {
type: 'SAVE_ITEM',
payload: {
request: {
url: '/save',
method: 'POST',
data: bodyFormData,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
},
},
};
}
However the request header's Content-Type not changing:
I tried changing case like content-type, I tried wrapping the headers into config: { headers: { 'Content-T... } } but non of them solved the problem.
How can I achieve to send the request with 'Content-Type': 'application/x-www-form-urlencoded'

Post data with By posting data with 'content-type': 'application/x-www-form-urlencoded' and 'key': 'key'

I want to post data to the server using headers content-type: 'application/xww-form-urlencode' but it fails because of the content type change to application/json
var headers= {
'content-type': 'application/x-www-form-urlencoded',
'x-access-key': 'key'
}
var data = {
'twins' : twins
}
axios.post('url', data, { headers: headers })
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
With Postman I successfully added the entry
In your headers change content-type to
'Content-Type': 'application/x-www-form-urlencoded'
If this doesn't work, then you I feel you might be using an interceptor. Which might be overriding your configuration.

Setting authorization header in Fetch API

I have a Node/Express backend and I'm consuming the API with a React Client. I want to be able to set the authorization header after a user is signed up. This ensures that subsequent requests are sent with the authorization header.
I can see how it's done in Axios here and how to retrieve the authorization header in Fetch here
Is it possible to do this with Fetch API and how?
Thank you in advance.
var url = "https://yourUrl";
var bearer = 'Bearer ' + bearer_token;
fetch(url, {
method: 'GET',
withCredentials: true,
credentials: 'include',
headers: {
'Authorization': bearer,
'X-FP-API-KEY': 'iphone', //it can be iPhone or your any other attribute
'Content-Type': 'application/json'
}
}).then(responseJson => {
var items = JSON.parse(responseJson._bodyInit);
})
.catch(error => this.setState({
isLoading: false,
message: 'Something bad happened ' + error
}));
As far as I know, there's no way to use default options/headers with fetch. You can use this third party library to get it to work, or set up some default options that you then use with every request:
// defaultOptions.js
const defaultOptions = {
headers: {
'Authorization': getTokenFromStore(),
},
};
export default defaultOptions;
Then use the default options like:
import defaultOptions from './defaultOptions';
// With default options:
fetch('/auth', defaultOptions);
// With additional (non-default) options:
fetch('/auth', { ...defaultOptions, body: JSON.stringify(additionalData) });
You can pass headers as second parameter of fetch:
fetch(<your url>, {
headers: {
authorization: <whatever is needed here>
}
})
headers: {
'Authorization': `Bearer ${localStorage.getItem("token")}`,
'Accept': 'application/json',
'Content-Type': 'multipart/form-data;
},
In my case, the problem was that the string I was setting as the Authorization was not yet generated. I had to wrap it in a promise, and suddenly it worked.
let authHeader: string = await SearchAuthService.getAuthHeader();

Resources