For some reason when I try to send a POST or PUT request, the server will receive GET. Tried multiple ways of sending the request but the result is always the same.
Here is an example that demonstrates the issue
$http.post(baseUrl + '/login',{username:usr,password:psw})
.then(
function (response) {
alert(JSON.stringify(response));
return { status: "OK" };
},
function (httpError) {
alert(JSON.stringify(httpError));
if(httpError.status == "401"){
return{ status:"UNAUTH" };
}
return { status:"ERR" };
}
);
$method = $_SERVER['REQUEST_METHOD'];
always returns GET no matter what. And even the body is empty.
Related
Is there a way to not just intercept but also respond to an axios request before it has been sent off? As in, send a request from the browser and respond to it from the browser + prevent it from sending request.
I know that I can use axios interceptors to intercept the request and response before it is sent and returned to the component and I know that in the request interceptor I can throw an error and trigger the response interceptor with a failed request. How can I do the same for a successful request? Given certain conditions I want axios to respond as if it passed to the server when it actually never made it past the interceptor. is this possible?
Here's pseudo code for what I've got so far:
axios.interceptors.request.use(
request => {
if (localResponse) {
throw { isLocal: true, data: { hello: 'world' } }; // <- this will stop request and trigger
// response error. I want to trigger
// the actual response callback
} else {
return request; // <- will perform full request
}
},
error => {
return Promise.reject(error);
}
);
axios.interceptors.response.use(
response => {
return response; // <- I want to trigger this callback
},
error => { // <- so far i can only trigger a response error
if (error?.isLocal) {
return Promise.resolve(error.data);
}
return Promise.reject(error);
}
);
I've tried just resolving the request interceptor but that tries to continue to fulfill the request. Does anyone have any creative ideas for solving this problem? Maybe there's a better solution than using interceptors?
Managed to compose a solution myself. This way all my axios calls will not have to be altered, i can just change behavior of interceptor.
NOTE: If anyone comes up with a better solution I will happily tag their answer as correct and upvote. For now this is the best solution I can come up with.
SOLUTION
Here's how i was able to resolve the problem
axios.interceptors.request.use(
request => {
if (localResponse) {
throw { isLocal: true, data: { hello: 'world' } }; // <- this will stop request and trigger
// response error. I want to trigger
// the actual response callback
} else {
return request; // <- will perform full request
}
},
error => {
return error?.isLocal
? Promise.resolve(error); // <- triggers response intercept
: Promise.reject(error);
}
);
axios.interceptors.response.use(
response => {
return response;
},
error => {
error?.isLocal
? Promise.resolve(error); // <- sends as successful response
: Promise.reject(error);
}
);
Essentially what I'm doing is throwing an error to prevent the request from going through, but then resolving the error instead of rejecting it. It's a little hacky but it gets the job done.
Can you just skip the request altogether in the local scenario?
function getData() {
if (localResponse) {
return Promise.resolve({ isLocal: true, data: { hello: 'world' }});
}
else {
return axios.whatever;
}
}
...
getData().then(...)
I am not sure what is going on here, but when I am sending back a 400, or some other error request back to the client, node is setting a generic message instead of the one I am sending back. Here is a snippet from my server and what gets put in the UI on the client
Server:
var noContentFound = {
error:true,
message:'No data found for this search'
}
res.status(400).send(noContentFound);
return;
Client:
.catch(function (error) {
let errorFromServer = {
generalServerError:{
error:true,
message:error.message
},
...
};
return errorFromServer;
//both error, and error.message give the message "Request failed with status code 400"
});
So I am sending back in my server noContentFound object with the error message in it through res.status(400).send(noContentFound); But in the client the only thing that is returned in the catch function is Request failed with status code 400 I dont have access to the message I am trying to send back.
Odd thing is, in the network tab on that call on the response tab I can see the object coming through. But error in the catch function does not give me access to that object.
Anyone know why?
EDIT:
Client Call looks like this:
Base Module:
getContent(obj, envBool, baseUrl, httpRequest)
.then(function(data){
//assign to my store object in react and emit the change
});
Where the call is made module:
const getContent(obj, envBool, baseUrl, httpRequest){
//set some variables and data to send
return httpRequest.post(enviUrl,objToSend)
.then(function(response){
returnObj = {
//assign returned data...
}
//...
return returnObj;
})
.catch(function(error){
returnObj = {
//assign and handle error...
}
//...
return returnObj;
});
}
Situation
From my Meteor.js website I'm calling my own REST service. Here's a code sample from my server side
function (question) {
var r = Async.runSync(function (done) {
HTTP.get(URL, {
params: {q: question}, headers: {
"Accept": "application/json",
}
}, function (err, result) {
done(err, result);
});
});
if (r.err) {
console.log("Failed to smartSearch ... ", r.err);
return null;
} else if (r.result.content) {
console.log("Success ... ");
return JSON.parse(r.result.content);
}
}
This works great but there is also some crucial information in the response headers which I'm unable to find.
What I've tried so far
I viewed everything within r.result.content, but this only contains my request headers.
I've installed https://atmospherejs.com/gadicohen/headers and tried everything the site said.
But still not seeing my response headers.
Additional Information
I'm fairly new to Meteor.js so I don't really have an idea what I might be doing wrong but getting response headers doesn't see like a strange thing to me.
There is no need to wrap the request as an async call, as it already is.
You can use a try..catch block to handle both successful and failed requests.
try {
var result = HTTP.get(...);
var responseHeaders = result.headers;
} catch (e) {
// handle error
}
If the response headers indicate JSON response, it will be parsed and available as result.data. The response will be available as a string in result.content.
More details are available in the HTTP package API docs.
Before making an HTTP request, I need to check if the access credentials I have are valid. If they are not valid, I need to make a first HTTP request to revalidate them and, after completion, then a second HTTP request (the original one). The function call needs to return Angular's $http promise from the second HTTP request. Here's my function:
var makeRequest = function (scope, address, request, basic, form) {
startLoad(scope);
// Check if user is logged in and needs a new session token...
if (ready() && (now() > getSessionExpires()-20) ) {
// Setup auth.session.refresh request
var refreshRequest = {
"refreshToken": getRefreshToken(),
"clientID": getClientID(),
};
// Make auth.session.refresh request
$http.post(API + 'auth.session.refresh', format(refreshRequest))
.error(function (data) {
// If refresh request fails, logout and redirect to expired message
stopLoad(scope); logoff();
$window.location.href = '/error/expired';
return;
})
.success(function (data) {
// If refresh request succeeds, makeRequest is called recursively and the else condition runs
process(data, true);
return makeRequest(scope, address, request, basic, form);
});
} else { // if not logged in, or if session token is valid, run request function as usual
// Add Authorization header with valid sessionToken
if (ready()) $http.defaults.headers.post['Authorization'] = 'Bearer ' + getSessionToken();
// Basic Request: returns promise (if next context not set, can chain other action)
if (basic) {
return $http.post(API + address, request)
.error(function(data) {
if (data && scope) stopLoad(scope, data.message);
else if (scope) stopLoad(scope, Defaults.serverError);
else stopLoad();
if (form) resetForm(form);
})
.success(function(data) {
process(data);
if (scope) {
stopLoad(scope);
if (scope.context.next) $location.path(scope.context.next);
} else stopLoad();
if (form) resetForm(form);
});
}
// Custom Request: returns promise (can chain .error, .success)
else return $http.post(API + address, request);
}
};
When the token is found to be invalid, however, the function returns undefined, and I get an error that I cannot run .success() or .error(). The else functionality runs, but I'm wondering how I can ensure that I don't get this error. Thank you!
Just return the upper $http.post(/*...*/) and let promise chaining do it's magic:
return $http.post(API + 'auth.session.refresh', format(refreshRequest))
.catch(function (response) {
// If refresh request fails, logout and redirect to expired message
stopLoad(scope); logoff();
$window.location.href = '/error/expired';
})
.then(function (response) {
// If refresh request succeeds, makeRequest is called recursively and the else condition runs
process(response.data, true);
return makeRequest(scope, address, request, basic, form);
});
UPDATE: since .success/.error functions are not chainable (and have been flagged deprecated), you should use .then and .catch instead.
$http.post(/*...*/)
.success(function(data) {
/* do something with data */
})
.error(function(err) {
/*...*/
});
becomes
$http.post(/*...*/)
.then(function(response) {
/*do something with response.data */
})
.catch(function(response) {
/*...*/
});
i'm having a specific problem with the error "Can't set headers after they are sent".
The code is this one:
create: (request, response, next) ->
socket = #app.socket
#
# This method will be used to call the right method inside
# the emails service.
data = JSON.stringify(
Object.assign request.body.data, method: 'server'
)
socket.send data
socket.on 'message', (result) =>
result = JSON.parse(
result.toString()
)
if result.code is 'success'
#model.insertAsync request.body
.then (result) ->
response.json data: result
return
.catch next
return
return
I'm using two servers and socket connection to communication between them. When i want create a email, i send a message for this other server and wait for the result, if the result is "success", i send the data back (i'm using Ember, so i need send the data after saving it). Now the problem: when i send the email for the first time everything works normal, when i try for the second time, a error message shows in my terminal:
Error: Can't set headers after they are sent.
According to express, the error is in this line:
response.json data: result
or in JS:
response.json({data: result});
The code in pure JS:
create: function(request, response, next) {
var data, socket;
socket = this.app.socket;
data = JSON.stringify(Object.assign(request.body.data, {
method: 'server'
}));
socket.send(data);
socket.on('message', (function(_this) {
return function(result) {
result = JSON.parse(result.toString());
if (result.code === 'success') {
_this.model.insertAsync(request.body).then(function(result) {
response.json({
data: result
});
})["catch"](next);
}
};
})(this));
}
Thanks in advance, guys!
Most likely what is happening is you are receiving more than one successful "message" and so it's calling response.json() multiple times.
You could fix this by changing on('message') to once('message') so that the event handler only executes once. However, if that one message is not successful, a response won't be sent. So you may need to either add an else to your if (result.code === 'success') or leave on('message') and introduce some sort of guard variable so that the code inside the if is only executed once.