XMLHttpRequest javascript POST-request issue "cannot load url" - javascript

var http = {};
http.request = (function () {
function send(jsonObject, url) {
var jsonString = JSON.stringify(jsonObject);
var req = new XMLHttpRequest();
req.open("POST", url);
req.setRequestHeader("Content-Type", "application/json");
req.send(jsonString);
}
return {
send: send
};
})();
I am trying to use this javascript function to send data. However it gives me an error:
"XMLHttpRequest cannot load url. Response for preflight is invalid (redirect)"
What am i doing wrong?

Since you are setting the content-type to be json, this is considered a preflighted request. What this means is that essentially two requests are being made: the first one asks the server permission to make a request, and the second one is the actual request. For such cases, you need to at least check for origin of the request on your server side:
header('Access-Control-Allow-Origin: your origin url')
You might also have to check the request method:
header('Access-Control-Allow-Methods: POST')

Related

Getting the Bad request error 400 trying to send XMLHttpRequest to http://api.lbs.yandex.net/geolocation

I need to send XMLHttpRequest to the Yandex server
I get the Bad Request error (400) and:
XMLHttpRequest cannot load http://api.lbs.yandex.net/geolocation. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost' is therefore not allowed access.
The response had HTTP status code 400.
Here is my code:
var xhr = new XMLHttpRequest();
var url = "http://api.lbs.yandex.net/geolocation";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function () {
<some code>
};
var data = JSON.stringify({
"common": {
"version": "1.0",
"api_key": <here goes API key>
},
"gsm_cells": [
{
"countrycode": params[0],
"operatorid": params[1],
"cellid": params[3],
"lac": params[2],
"age": 0
}
]
});
xhr.send(data);
I can't find the solution for such a simple(?) thing!
That API expects application/x-www-form-urlencoded-formatted data that looks like this:
json={"common":{"version":"1.0","api_key":…}…}
That is, it needs a key=value pair, with the string json as the key and some JSON as the value.
But the code in the question is sending some JSON without the necessary json= preceding it. So the API endpoint responds with a 400 to tell you it’s a bad request.
So you can fix that and get a response back by making your code instead do this:
var data = 'json=' + JSON.stringify({…});
However, even after you do that, your browser’s still not going to let your frontend JavaScript access the response the server returns. Instead the browser will log an error message like this:
Failed to load https://api.lbs.yandex.net/geolocation: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin https://foo.bar is therefore not allowed access.
…because the CORS protocol requires browsers to disallow frontend JavaScript code access to responses from cross-origin requests unless the response has Access-Control-Allow-Origin.
But you can get around that by making the request through a CORS proxy; complete example:
var xhr = new XMLHttpRequest();
var proxyurl = "https://cors-anywhere.herokuapp.com/";
var url = "https://api.lbs.yandex.net/geolocation";
xhr.open("POST", proxyurl + url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
console.log(xhr.responseText)
};
var data = 'json=' + JSON.stringify({
"common": {
"version": "1.0",
"api_key": "AAwkGkwBAAAA9muWLAMAKp9XjTBZtmOLeiBQJqHX6YEqNdUAAAAAAAAAAAAoEP1ZsBlcVFA_OpP55MK3Ek1r8A=="
},
"gsm_cells": [{
"countrycode": 250,
"operatorid": 99,
"cellid": 42332,
"lac": 36002,
"age": 0
}]
});
xhr.send(data);
Note however that if you send the request through a third-party proxy like that, the operator of the proxy can potentially snoop on your api_key and any other credentials you might send.
So you’re better off setting up your own proxy using https://github.com/Rob--W/cors-anywhere/
As far as how the proxy in example above works: Prefixing https://cors-anywhere.herokuapp.com/ to your request URL causes the request to get made through that proxy, which then:
Forwards the request to whatever https://api.lbs.yandex.net/geolocation.
Receives the response from https://api.lbs.yandex.net/geolocation.
Adds the Access-Control-Allow-Origin header to the response.
Passes that response, with that added header, back to your requesting frontend code.
The browser will then allow your frontend code to access the response, because that response with the Access-Control-Allow-Origin response header is what the browser sees.
See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Suggested sulution will not work correctly in common case, but works correctly for gcm cell. It's because yandex.net/geolocation service used to getting location of user based on WiFi network, gcm cell or ip address.
When need use only IP based way then required configuration CORS on your web server.

Unable to retrieve data from http site to https using XMLHttpRequest()

I have a site hosted on https:// in which I want to pull data from the site which shows the properties of the shares. The URL which returns the data is:
http://ir1.euroinvestor.com/asp/ir/xmlirmultiiso2.aspx?companyid=281191
The code which I have developed to get the data is as follows:
function GetSharesUpdate(){
// makeing AJAX calls to the web service for getting the share update
var xhr = new XMLHttpRequest(); // Set up xhr request
xhr.open("GET", "http://ir1.euroinvestor.com/asp/ir/xmlirmultiiso2.aspx?companyid=281191", true); // Open the request
xhr.responseType = ""; // Set the type of response expected
xhr.send();
// Asynchronously wait for the data to return
xhr.onreadystatechange = function () {
if (xhr.readyState == xhr.DONE) {
var tempoutput = xhr.responseXML;
alert(tempoutput);
}
}
// Report errors if they happen
xhr.addEventListener("error", function (e) {
console.error("Error: " + e + " Could not load url.");
}, false);
}
I am getting the error on the statement xhr.send(); which is as below:
Mixed Content: The page at 'https://[SiteUrl]' was loaded over HTTPS,
but requested an insecure XMLHttpRequest endpoint
'http://ir1.euroinvestor.com/asp/ir/xmlirmultiiso2.aspx?companyid=281191'.
This request has been blocked; the content must be served over HTTPS.
If I change the URL to https i.e.
https://ir1.euroinvestor.com/asp/ir/xmlirmultiiso2.aspx?companyid=281191
then xhr.send(); is executed without any error but I am getting xhr.responseXML null.
What should I make changes in my code to make it working?
The first problem is you are doing ajax request to non-https domain but your domain has SSL installed.
The second problem is Cross origin request CORS, you will have this problem even you solve first (ie. even you try ajax request from non-http domain).
Since you are requesting data from another website this is most likely to happen unless the requested server is configured to serve requests for you domain
To solve this you need to call the data from your server(proxy server) or have the requested server configured to allow requests from your domain.
See more - https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Unable to authenticate rest call through XMLHttpRequest

I have been using postman to test an API which, I am successfully able to call.
When I try to execute this call through javascript I get an authentication error.
The URL and authorization match that of the postman call and when I call using these details with curl I am able to retrieve the correct data.
<script type="text/javascript">
var data = new FormData();
data.append("attributeId", "");
data.append("validFrom", "");
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http:/restpAPI/test");
xhr.setRequestHeader("authorization", "Basic asdsadsadjlafdkfjkldfj==");
xhr.setRequestHeader("cache-control", "no-cache");
xhr.setRequestHeader("postman-token", "dsadasd-asdsad-asd-asd-aasd");
xhr.send(data);
</script>
When I run a local web page with this script I get a 401 saying Unauthorized.
What is the difference between the JavaScript code and postman or cURL and is there a way of authenticating from JavaScript?
Update
I have discovered that setting the RequestHeader with the authorization key turns the request from a get to an options. This is causing the error.
Although HTTP Headers are supposed to be case insensitive, have you tried setting the headers' names with title case (Authorization)?

How to get rid of No 'Access-Control-Allow-Origin' header is present on the requested resource error in java based web-service server

I'm trying to build a webservice (Java based server and Javascript base client) I only need to send a Post request with json data and I need to get a post response with json data from server.Since client and server have different domains I think cors need to be supported. Up to now, I've implemented these: (My client implementaion is almost same with html5 rocs tutorial)
Web service client (js):
// I call client = new WSclient() in one of my js files
WSclient=function(){
makeCorsRequest();
}
// Create the XHR object.
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
}
// Helper method to parse the title tag from the response.
function getTitle(text) {
return text;
}
// Make the actual CORS request.
function makeCorsRequest() {
// All HTML5 Rocks properties support CORS.
var url = 'http://localhost:8080/myapp/myfunction';
var xhr = createCORSRequest('POST', url);
xhr.setRequestHeader(
'X-Custom-Header', 'value');
xhr.send();
}
Web service server (java)
#Path("/myapp/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class myFunctionClass {
#POST
#Path("myfunction")
public Response recommendations(User inf){
// From the client I also need to send json
// like {"name":"john","surname":"smith","name":"marry","surname":"smith"}
// and if possible I want to put this infformation inside inf object
List<String> infos = inf.getInformation();
// here I call one of the my methods to get recommendations
// I remove it for simplicity and just put type of recommendations object
// list<Recommendation> recommendations= runFunction(infos);
final StringWriter sw =new StringWriter();
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(sw, recommendations);
System.out.println(sw.toString());
sw.close();
return Response.ok(sw.toString(), MediaType.APPLICATION_JSON).header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "POST").allow("OPTIONS").build();
}
}
However, I think I need to do something more because when I run these, I got
XMLHttpRequest cannot load http://localhost:8080/myapp/myfunction.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed access.
So what should I add to my server code to get rid of this error? Besides, how could I send json data inside my request in client? This is my first time dealing with such issues therefore, If my question a bit absurd, sorry about that.
EDIT
When I remove
xhr.setRequestHeader(
'X-Custom-Header', 'value');
part from the client, It works properly. As I said before, this is my first time with web-services and javascript so actually I dont know what does this line of code. Could anyone explain me what happens if it exists or not?
EDIT2
I understood that, I need to put
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
in order to send a json with request.But when I added this, same errors come back. What should I add to server to achive this ?
What's happening is that there is a preflight request (which is an OPTIONS request), made before the initial request. So you need an #OPTIONS endpoint to handle that request (i.e. set the response header). In your current code, you are trying to set it in the original requested endpoint response, where the OPTIONS request won't even reach.
A more common approach, instead of creating an #OPTIONS endpoint for each target, just use a Jersey filter as seen in this answer. The headers will get sent out for all request.
See Also:
HTTP access control (CORS)
EDIT
Example #OPTIONS
#OPTIONS
#Path("myfunction")
public Response cors() {
return Response.ok()
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD")
// whatever other CORS headers
.build();
}

CORS: Can't get POST request body.

I am trying to make request with XMLHttpRequest from file://example.html to http://localhost/index.php. I read a lot about CORS(in this case origin is null, this is OK.) and i have no idea what i am doing wrong.
My request finishes well but the $_POST is empty! Except if i set "Content-type: application/x-www-form-urlencoded". But "text/plain" or "application/json" gives no result in $_POST... Why?
xhr.open("POST", "http://localhost/index.php", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = handler;
xhr.send({'a':'12'});
You are probably doing one of these two things wrong:
If the content-type is not application/x-www-form-urlencoded, CORS must send a preflight request. That means that the browser will send before doing the POST request an OPTIONS request, which is used to determine if the POST request is allowed. Take a look here how this works.
Secondly, if you use xhr.setRequestHeader("Content-Type", "application/json"), the $_POST parameters will not be filled with parameters, this is only the case for application/x-www-form-urlencoded. To get the JSON you send, you will have to do:
<?php
$input = json_decode(file_get_contents("php://input"), true);
echo $input['a']; //echoes: 12
For more info, see this question.
Furthermore, if you go into the debugging facilities of any decent browser, it will create an error message if the CORS request is not allowed, please be sure to check if the CORS request was actually made by the browser.
I hope this helps you.
complementing #user23127 response
server side should have something like this to respond to the OPTIONS preflight request:
if (request.method === 'OPTIONS') {
htmlRes = HttpResponse()
htmlRes['Access-Control-Allow-Origin']='*' // or your not origin domain
htmlRes['Access-Control-Allow-Methods']='*' // or POST, GET, PUT, DELETE
htmlRes['Access-Control-Allow-Headers']='*' // Content-Type, X-REQUEST
}
// the rest of the code as if it was not a CORS request

Categories