I have an express app with some ajax, calling some remote endpoints. At the moment, my api calls are posting to an endpoint on my local server. Express listens on these endpoints and pipes the request to the remote server and resolves the response.
This is working for most of my endpoints, except for one POST method which requires a query parameter of code and a body of type Array[int]. The response for each request to this endpoint returns 405. If I call the server endpoint directly within the ajax request, It returns successful. Does this issue ring a bell for anyone?
Here is what the data flow looks like.
$.ajax({
type: "POST",
url: "/promos/validate?code=testing",
data: JSON.stringify([1]),
success: function(data) {
console.log(data)
}.bind(this),
error: function(xhr, status, err) {
console.log(status)
}.bind(this)
});
And then we route with express
router.post('/promos/validate', function(req, res) {
pipe(req, res).post(http://remoteUrl/promos/validate/code=testing);
});
In the post method, lives the http.request function which sends the following object as the options parameter
{
protocol: 'http:',
query: '?code=testing',
host: 'remote-api.com',
port: 80,
hostname: 'remote-api.com',
href: 'http://remote-api.com?code=testing',
path: '/promos/validate',
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Content-Length': 8 }
}
And finally we stream the request body to the server with write. Every time this happens, it returns 405. Any ideas?
Two things: the ajax request needed to set the content type to application/json and it turns out that the request was hitting 405 because the query was being separated into its own property when it should have been appended onto the 'path' property option.
I found this out by viewing the options list at Node.js docs - https://nodejs.org/api/http.html#http_http_request_options_callback
Related
I'm using Axios library to make an API call in my React application.I call the API and then populate a table using React.
My Axios call is as follows:
axios({
method: 'get',
url: DataURL,
headers: {
'Content-Type' : 'application/json',
'Id': user.Id,
'Name' : user.Name,
'api-token' : user.access_token,
'clientId' : 'web',
},
responseType: 'json',
})
.then((response) => {
this.setState({ tableData: response.data });
});
However I get this error:
XMLHttpRequest cannot load MY API URL Response for preflight has invalid HTTP status code 400
The same was working in my dev environment where I wasn't adding any headers, however after migrating to new env which required me to add headers, Im getting the above error.
My question is, is this a client side issue(like wrong header format etc) or is it something to do with server side handling of the API call?
I think this is a server-side issue. If you are using node in the background you need CORS as a middleware (https://www.npmjs.com/package/cors).
For other server solutions there are of course also cors request handler.
I have a route
Route::post('/updateLogo', 'CaptivePortalController#updateLogo');
Then I make a POST here
$http({
method: 'POST', <----- I did a POST
url: '/updateLogo',
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
console.log("data coming into the transform is ", data);
var formData = new FormData();
formData.append("company_logo_path", data.files);
console.log($scope.files.company_logo_path);
return formData;
},
data: { files: $scope.files.company_logo_path }
})
.then(function successCallback(response) {
console.log("success");
console.log(response);
$('.save-fade').delay(500).fadeOut(1000);
}, function errorCallback(response) {
console.log("fail");
console.log(response);
});
When I browse the file, and submit the form, I kept getting
405 in my Network tab on Chrome Dev Tool.
Then, I click on it, I see
MethodNotAllowedHttpException in RouteCollection.php line 218:
I know that I'm NOT suppose to make a GET to a POST route, but Why does it make a GET request instead of a POST?
Request URL:http://l.ssc.com:8888/en/updateLogo
Request Method:GET <------
Status Code:405 Method Not Allowed
Remote Address:127.0.0.1:8888
Referrer Policy:no-referrer-when-downgrade
What did do wrong here ?
Any hints ?
This looks like a re-direction taking place.
refer : $http.post() method is actally sending a GET
Please check your route configuration at the server, make sure it is exactly the same as you're requesting.
If you're requesting a '/myroute' but you've defined the route as '/myroute/' then your server could be redirecting to '/myroute'.
All re-directions are done using a GET.
And since the route doesn't allow GET request, it's returning a 405.
I have an Ionic App that I am using restangular to communicate with a node express application.
Everything is working when I have the node express application configured to use http.
Ionic App side:
RestangularProvider.setBaseUrl('http://11.22.33.44:3000');
// custom header
interceptors.serialNumber = function (element, operation, what, url, headers, query) {
return {
headers: angular.extend({
'x-serialnumber': deviceStore.serialNumber
}, headers)
};
};
Restangular.one(‘Admin’).get()
.then(function (data) {
console.log(data);
}, function (error) {
console.log(error);
});
Node Express App side:
var app = express();
app.use(cors());
app.get('/Admin, function(req, res) {
console.log(admin-get');
res.send(200);
});
I was expecting I would need to handle a pre-flight request since the cors node module states: “An example of a 'complex' CORS request is one that uses an HTTP verb other than GET/HEAD/POST (such as DELETE) or that uses custom headers.” So I am not sure why this works?
I reconfigure the Ionic App and Node Express App to use a https address instead of a http:
Ionic App side:
RestangularProvider.setBaseUrl('https://11.22.33.44:3000');
// custom header
interceptors.serialNumber = function (element, operation, what, url, headers, query) {
return {
headers: angular.extend({
'x-serialnumber': deviceStore.serialNumber
}, headers)
};
};
Restangular.one(‘Admin’).get()
.then(function (data) {
console.log(data);
}, function (error) {
console.log(error);
});
Node Express App side:
var app = express();
app.use(cors());
app.get('/Admin, function(req, res) {
console.log(admin-get');
res.send(200);
});
when the Ionic App performs the GET request, I see in the Chrome debugger under “Network” an OPTIONS request that gets canceled (request’s status). This tells me that I need to enable cors pre-flight on my Node Express App side (though why didn’t I see this error when the server was configured with http instead of https?).
So I tried the following on the Node Express App side per the express js cors module documentation:
app.options('Admin', cors()); // enable pre-flight request
app.get('/Admin', cors(), function(req, res) {
console.log('admin-get');
res.send(200);
});
I see the same thing in the Chrome debugger under “Network” - a OPTIONS request that gets canceled (request’s status). I also tried
app.options('*', cors());
with the same result.
I then removed the insertion of the custom header (x-serialnumber) on the Ionic App side. It now works.
So why would the Node Express Application work when configured with a http address with out handling a pre-flight request I would expect due to the insertion of a custom header on the Ionic App side?
When the Node Express App is configured with a https address (as well as Ionic App side) why am I not handling the OPTIONS request? Is the way I am configuring cors incorrect? What am I missing?
I think it is a cors issue since I can eliminate the custom header on the Ionic App side when they are configured for a https address and it works.
What do I need to do to get this working?
UPDATE
I tried using Angular JS $http instead of Restangular. I got the following result which works:
$http({
method: 'GET',
url: theUrl
}).then(function successCallback(response) {
$http({
method: 'GET',
url: theUrl,
headers: {
'x-serialnumber' : deviceStore.serialNumber
}
}).then(function successCallback(response) {
}, function errorCallback(response) {
});
}, function errorCallback(response) {
});
I see in Chrome Network Debugger the first GET (minus the custom header) goes out and I get a good response (200), followed by the OPTIONS request where I also get a good response (200), followed by a good GET with the custom header in it (get good response back).
If I do NOT do this first GET request minus the custom header, the OPTIONS request aborts on the Angular JS Ionic App side with a status of -1.
NOTE: I can change out the initial $http request (minus custom header) for a Restangular request (minus custom header)
Why is this initial GET minus the custom header needed (i.e. GET (minus custom header) | OPTIONS | GET (with custom header))?
What do I not understand?
Well what I needed to do was the following:
$http({
method: 'GET',
url: 'https://example.com/DUMMY'
}).then(function successCallback(response) {
$http({
method: 'GET',
url: 'https://example.com',
headers: {
'x-serialnumber': deviceStore.serialNumber
}
}).then(function successCallback(response) {
console.log('SUCCESS');
}, function errorCallback(response) {
console.log('FAILURE');
});
}, function errorCallback(response) {
console.log('FAILURE');
});
In essence, I needed to send a "preliminary" GET request with NO custom header. The GET request could be to anything on my node express server. After this "preliminary" GET request, I could perform the GET request with the custom header in it.
Specifically on the server side I see the following:
GET /DUMMY 200 10ms - 2b
OPTIONS / 204 1ms
GET / 200 13ms - 1.03kb
Without performing this "preliminary" get request, the OPTIONS request in my Ionic App would abort - status code = -1 - usually means the request was aborted and would never leave Ionic App side.
I still do not understand why I need this "preliminary" GET request, but this works for me.
Suppose that I have following angular http request which redirects to a route in the server side (node/express) to perform another http request to web api.
Based on the following code:
Would the angular http request will ever have errorCallback? If yes, under what situation?
What is a possible condition for the if(error) to produce an error in the server side http request? Is it client side http error? Any other else?
Should the http request in server side have error as true, will the app crash?
Angular http request:
$http({
method: 'GET',
url: 'webServerUrl'
}).then(function successCallback(response) {
alert('success');
}, function errorCallback(response) {
alert('fail');
});
Server side http request
var request = require('request');
exports.getSearchResults = function (req, res) {
request({
method: 'POST',
url: 'apiUrl'
}
, function (error, response, body) {
if (error) {
res.jsonp('Unknown error. Please try again later');
}
else {
res.jsonp(body);
}
}
)}
Would the angular http request will ever have errorCallback? If yes, under what situation?
Yes. If the request to the server times out or fails, it will be called.
What is a possible condition for the if(error) to produce an error in the server side http request? Is it client side http error? Any other else?
No, it will only cause an error if the call to the api fails.
Should the http request in server side have error as true, will the app crash?
No, it shouldn't. The error object is an object, not a boolean.
By the way, you should know that it is not standard practice to issue a GET request in the client and then issue a POST request to your api. A POST request implies some sort of state change, whereas a GET should not. Either make them all GET, if the calls can be made repeatedly without any side effects, or make them all POST.
I'm looking for a code example creating a REST POST request with JQuery on Neo4j 2.2.x Transactional Cypher HTTP endpoint with new REST API Authentication and Authorization parameters.
Before Neo4j 2.2 version I used the Legacy Cypher HTTP endpoint (which is deprecated) to execute Cypher queries with the following code:
$.post("http://localhost:7474/db/data/transaction/commit",
{
"query": query,
"params": {}
}, "json")...
But I would like to move to 2.2 and use the transactional endpoint with user authentication parameters.
I can't find the right headers and parameters combination to use to create such a request. That's why I'm looking for a code example.
Best would be an example using a cross domain request but an example on same domain would be helpful too.
For authentication you need to supply an additional HTTP header to your request:
Authorization: Basic realm="Neo4j" <base64>
where <base64> is the base64 encoded string of username:password.
Not being a jquery ninja, but I guess the most simple way is to set the authorization header using ajax defaults:
$.ajaxSetup({
headers: { "Authorization": 'Basic realm="Neo4j' <base64>'}
});
When this default has been applied your $.post above should work.
The issue has been fixed in 2.2.0-RC01 and I can use transactional Cypher HTTP endpoint with authentication using the following example code:
$.ajaxSetup({
headers: {
// Add authorization header in all ajax requests
// bmVvNGo6cGFzc3dvcmQ= is "password" base64 encoded
"Authorization": "Basic bmVvNGo6cGFzc3dvcmQ="
}
});
$.ajax({
type: "POST",
url: "http://localhost:7474/db/data/transaction/commit ",
dataType: "json",
contentType: "application/json;charset=UTF-8",
data: JSON.stringify({"statements": [{"statement": "MATCH (n) RETURN n LIMIT 10"}]}),
success: function (data, textStatus, jqXHR) {
// use result data...
},
error: function (jqXHR, textStatus, errorThrown) {
// handle errors
}
});
Authorization means that the browser will send a preflight OPTIONS request which does not embed authorization headers.
This is most known as CORS.
Currently the Neo4j server do not reply to the OPTIONS request with the appropriate Access-Control-Allow-Headers.
This feature has been implemented in the source code and will be shipped with the GA release which I hope will come out this week.