I'm not getting an error but when I saw the logs of my server it prints an empty object {} whenever I send a request to the sever from my react app using axios. I double checked everything every other request in another components of my app works fine, but only in this particular request the data is not being sent! I have no CORS issue!
My react axios request
// PrivateAxios instance to send api request
const axiosPrivate = useAxiosPrivate();
const handleSearch = async () => {
const data = JSON.stringify({ from_company: keyWord });
try {
const response = await axiosPrivate.get(SEARCH_URL, data);
console.log(response);
setRecords(response?.data);
} catch (err) {
if (!err?.response) {
console.log("NO SERVER RESPONSE");
} else {
console.log("SOMETHING WRONG");
}
}
};
Server log
{} <-- Prints the request.data as an empty object
"GET /api/find_many/ HTTP/1.1" 200 6276
The django server responses with correct details when I send a request with Postman or Thunder Client. The server also prints the object that were sent with the Postman request. I don't know why the server is unable to get the object or data when I request from my react app.
Request sent from Postman returns
{'from_company': 'Jethmal Paliwal'} <-- Prints the request.data correctly
"GET /api/find_many/ HTTP/1.1" 200 2284
I have double checked everything, my headers are set correctly, Content-Type: application/json, withCredentials: true, and every other possible settings, Even every request from other components works great, but why this particular request doesn't reach the server?
Tried writing the data as an Object in the request funcion itself
const response = axiosPrivate.get(SEARCH_URL, { "from_company": "Jethmal Paliwal" }); which doesn't work as well. The same empty object gets printed.
Tried JSON.stringify the data, which doesn't work as well.
I believe that axios is omitting the data as it's not per REST standard to submit data in the GET request. HTTP allows that, but people and apparently libraries are not expecting it.
This is the API for axios get method:
axios.get(url[, config])
as you see there is no data in the method signature. And if we look at the POST method:
axios.post(url[, data[, config]])
I suggest if you have data to submit to server that you use a POST method instead.
Related
I set up passport-local to login a user, and then once logged in, the user will be given a JWT token through passport-JWT. The JWTStrategy is set up to use
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken() so that the JWT can sent with the Authorization header Authorization: `Token ${userContext.token}`}. In my react client side, I have set up a GET request using axios as shown here:
const fetchProfileDetails = async(config)=>{
const res = await axios.get("http://localhost:8080/users/me", config)
}
const config = {
method:"GET",
withCredentials: true,
headers: {Authorization: `Bearer ${userContext.token}`}
}
This request successfully authenticates and returns the user data from /me.
Now heres the kicker: when I use the exact same request structure, but switch the method to post in the axios request and in my express route in the backend, the request always responds with a 401 Unauthorized.
However, when I send the same request from POSTMAN, with the same Bearer Token used in the request that was Unauthorized, the request succeeds without any errors.
TLDR: GET requests work with the JWT token and return with a 200 status code, while the same request with a POST method returns with a 401 status code.
What am I missing here??!
You are probably using there GET and not using POST anywhere.
In your code, you have code only for get. You will need to write code for post as well.
Below is the code for post for your reference:
router.post('/', config, async(req, res, next) => {
const { error } = validateBody(req.body);
if (error) {
return res.status(400).send(error.details[0].message);
}
const newData= new passport({ name: req.body.name });
await newData.save();
console.log('saving the document');
res.send(newData);
})
Your code should have post as well. Writing single code will not work. You need to have to write code for every condition and every possibility. So like for get need code for post as well, also if you have condition for patch or delete or put you will have to write the axios method for that as well.
Hope this has helped you in any way.
I have come upon a solution for this issue. For some reason, axios was not maintaining the Authorization header I had set in my config variable, and deleted it upon making the request. To solve this, I just had to reshuffle my axios request to look like this:
const res = await axios({
method:'POST',
url:"http://localhost:8080/users/test",
headers:{'Authorization':`Bearer${token}`
}})
I feel cheated as I spent a ton of time on this and the solution was so underwhelming. Axios was trolling me the whole time :/
The long short is...
My express backend sets a cookie and sends it back to the client, everything works great when I use Postman and my React Native app. The issue is the web version which is done via ReactJs makes the same request but cookie is stored in the browser.
So I know cookies are working but not for the web version which is strange when I created a test endpoint http://localhost:3000/server and call it straight from the browser the cookie is stored.
So this is my code doing a simple fetch to the server which then sends back a cookie:
const fetchData = async () => {
try {
const res = await fetch(`http://192.168.0.11:3000/server/`, {
credentials: "include",
});
if (res.ok) {
const resData = await res.json();
console.log({ resData });
}
} catch (err) {
console.log({ err });
}
};
The request came back successful but no cookie is stored
Access the same endpoint from the browser directly results in this:
An extract from the response header while being sent shows that the cookie was sent in the response just not stored in the frontend
Was a pretty simple fix
I was using http://localhost:3001 for the react app I just simply used the ip address instead http://192.168.0.11:3001
i can send file "userPicture" from postman and get it in the backend (springboot )and i save it to my database mongodb without any problem
but when i send the picture from the form i use Formik component in reactjs and axios
i display the content of my input userPicture i get
in axios i made this to sent the request. for boundary i dont know what is i made copy past "WebKitFormBoundaryQ0pBuvRC1EzDAQWT" from an exemple
try {
const { user } = action;
console.log(user);
const request = yield axios({
method: 'post',
url: ENDPOINTS.USER + '/add',
data: user,
headers: { 'Content-Type': 'multipart/form-data;boundary=----WebKitFormBoundaryQ0pBuvRC1EzDAQWT----' }
});
in the backend i get this error
,org.springframework.validation.BindingResult,org.springframework.web.multipart.MultipartFile,org.springframework.web.multipart.MultipartFile)
throws java.io.IOException: Required request part
'userPicture' is not present
i get the same error in postman when i send request without userPicture parameter
Looks like you sending the file incorrectly. If you want to send multipart/form-data from client to server, you need to use FormData.
Like this
const formData = new FormData();
formData.append('usePicture', user)
I have a redux store set up with actions to handle loading accounts. The action calls a service like so:
const requestOptions = {
method: 'GET',
headers: authHeader()
};
return fetch(`http://localapi.co.uk/api/account/load/${account_id}`, requestOptions)
.then(handleResponse)
.then(account => {
if(account.account.id) {
localStorage.setItem('account', JSON.stringify(account))
}
return account;
})
.catch(redirectToLogin)
Handle response is simply a function that checks the .status and .ok properties of the response and either displays an error or logs out if the response status is 401. This works perfectly fine for POST requests. When I hit my login route, any response hits the first .then(handleResponse) and deals with it.
When I send a GET request instead like above 404s, 401s, 500s.. etc all skip the .then(handleResponse) and instead jump to my catch. The problem that causes is that because catch doesn't actually give me a response object to work with I can't check the status - I want to do different things depending on whether the get was a 401 (I want to logout) or a 500 (I want to display a user error stating what went wrong) for example.
Is there a solution that will allow me to get a response or stop my GET requests hitting the .catch and instead hit the response handler I've written?
I'm using:
a Laravel 5.7.20 back-end
a React 16.7.0 front-end
running local node server with npm start
How about having a clean async/await function. Waiting till you JSON data becomes ready and then having the rest of your if logic or returning the account object from the function and moving the rest of the logic to the caller function. Something like this:
async myFunc({ account_id}) {
const url = `http://localapi.co.uk/api/account/load/${account_id}`;
const response = await fetch(url, { headers: headers: authHeader() });
const account = await response.json();
// return account (recommended);
// Place your if logic here (not recommended because its not clean)
}
I have a client running on Angular + typescript.
I need to send a post request to a php API (which I developed). The request arrives correctly to the server and the server fills the response body with the correct data (I have checked it myself debugging the server).
The issue is that, when the server responds, the angular promise executes the error callback and the response data is empty. When I check the sent request in the browser it says it was answered with a 200 OK status but it has an empty body.
I have tried calling the same API endpoint with the same paramentres through Firefox Api-requester addon and i recieve the response with the correct body... why is my Angular client not succeeding then?
The following code fragment corresponds to my controller:
vm.query = {
'tx_filtre':'', 'idioma_filtre':'', 'tipus':'', 'id_dimfisica':'', 'tamPag':15, 'numPag':0
};
this.PropietatsService.getPropietats(vm.query)
.then((response: ng.IHttpPromiseCallbackArg<string>) => {
vm.objResult = JSON.parse(response.data);
vm.propietats = vm.objResult.info;
console.log('rebut', this.propietats);
}, (response: ng.IHttpPromiseCallbackArg<string>) => {
//always executes this error function, why????
vm.objResult = JSON.parse(response.data);
});
And this is the relevant code for the service:
getPropietats(query: any): ng.IPromise<ng.IHttpPromiseCallbackArg<string>> {
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
};
return this.$http.post("http://localhost:8080/diccionaris/propietat/get",JSON.stringify(query),config);
}
On a side note, for some reason my server can't process the request if I set the request 'Content-Type' to 'application/json' in my client. That is the reason why I have set it to 'application/x-www-form-urlencoded'.
You set 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;', but you encode query params to JSON and then you try to decode a response like JSON. Try set application/json or try to remove JSON.encode request params and send to post method query.
If it doesn't help log error (in response) in error callback and look at it
If the server is not capable of accepting application/json, then the POST data needs to be encoded for application/x-www-form-urlencoded. To do this use the $httpParamSerializer Service:
getPropietats(query: any): ng.IPromise<ng.IHttpPromiseCallbackArg<string>> {
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
},
transformRequest: $httpParamSerializer
};
return this.$http.post(url,query,config);
}
I finally found the solution: it was a CORS problem.
I was running my server and my client in two different localhost ports so, although the server processed the request (which doesn't make much sense to me), it wasn't returning the response because the client was not allowed to access the server. To deal with it for now I've added the following line to my server index.php:
header('Access-Control-Allow-Origin: *');
And now it works just fine.