I am looking for a way to allow browser-hosted JS app to make requests to server running on different port and, possibly, different machine than that which is serving up JS app in the first place.
I am serving a simple JavaScript (HTML5) app from my Mac OS X Apache web server. I would like to be able to run this app in as many browsers as possible across Windows, Android and OS X. But I would settle for one on each.
My JavaScript app uses XMLHttpRequest to make requests of a minimal custom server that returns JSON.
So, for example, my JS app is accessible at http://10.0.1.3/poc/dashboard.html
and my custom server is running on same machine, listening on port 49379 ... a request like this http://10.0.1.3:49379/find?name=Fred would return a set of tuples where 'name' equals 'Fred'.
If I enter this request directly into navigation toolbar, then I get desired result.
If I make same request within JS, I get a couple of errors.
var theXHR = new XMLHttpRequest();
theXHR.onreadystatechange = onReadyStateHandler;
theXHR.open("GET", "http://" + ipAddress + ":49379/find?name=Fred", true);
theXHR.setRequestHeader("User-Agent", "XMLHTTP/1.0");
theXHR.send(null);
I get these two errors:
Refused to set unsafe header "User-Agent"
XMLHttpRequest cannot load http://10.0.1.3:49379/find?name=Fred.
Origin http://10.0.1.3 is not allowed by
Access-Control-Allow-Origin.
I have control over Apache server, JavaScript and custom server. This is just a proof of concept piece that will be demoed on isolated networks. So, I am not concerned with security issues.
Also, I am running in Chrome, Firefox, Safari. All of these appear to use the XMLHttpRequest2 object.
I have found the way to get around CORS is to use jsonp - which is json with a callback function - I've never used it with XMLHttpRequest, but it works with jQuery ajax functions like $.getJSON. In your url query string simply add the parameter jsoncallback=? and voila, no more CORS problems. $.getJSON dynamically assigns its success parameter to the callback function.
Related
This question already has answers here:
How does the 'Access-Control-Allow-Origin' header work?
(19 answers)
Why doesn't adding CORS headers to an OPTIONS route allow browsers to access my API?
(36 answers)
Closed 4 years ago.
I am using Angular 5 in my ionic app. I am trying to call a endpoint from my code
ngOnInit(): void {
//Called after the constructor, initializing input properties, and the first call to ngOnChanges.
//Add 'implements OnInit' to the class.
this.httpClient.get('https://abc-66b76.cloudfunctions.net/getBillNo', {
headers: {
'Access-Control-Allow-Origin': '*'
}
}).subscribe(data => {
console.log('firebase bill No: ', data);
this.bill.billNo = data.billNo;
})
}
When my page loads the above code is called and in chrome browser console i get the below error:
Failed to load https://abc-66b76.cloudfunctions.net/getBillNo: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.
However if i check my network tab in my chrome browser i can see that it has hit the server and has got the response.
Can anyone help me resolve this.
My Backend is firebase functions.
There's nothing to do in your Angular code. To make it working you need to either
Host your Angular code in https://abc-66b76.cloudfunctions.net (port 443) along with your backend
or
You need to allow your Angular hosted origin (in your case http://localhost:8100) in backend's Access-Control-Allow-Origin header (or * to allow all origin). Modern browsers verifies this and blocks requests in case this header is not present when cross-origin requests are performed for security considerations.
The way you set this header depends on your backend programming language.
if you use NodeJS + express
var cors = require('cors')
var app = express()
app.use(cors())
If the backend is not under your control, You can also tell your browser to ignore doing it.
Each browser would have a way to do it.
For chrome, Start chrome browser with --disable-web-security command line param (kill all running chrome instance).
A simple chrome extension can be used to do the magic (read its instructions) https://chrome.google.com/webstore/detail/cors-toggle/jioikioepegflmdnbocfhgmpmopmjkim?hl=en
If you are going to provide the Angular app for public then you should consider Adding the header or have a proxy for the backend and make requests via proxy, since you can't force each users to disable web security.
You probably need to do a proxy server, to avoid CORS when call api from localhost in development environment, so nodejs is a simple approach to make it, I really recommend you this post, it's simple to understand and easy to follow.
https://codeburst.io/using-nodejs-as-a-proxy-for-angularjs-ajax-requests-8e5e94203e0d
I found the easiest way is to use the node.js package cors. The simplest usage is:
var cors = require('cors')
var app = express()
app.use(cors())
There are, of course, many ways to configure the behavior to your needs; the page linked above shows a number of examples.
I am trying to build a quick demo site that I do not have control over the server I am trying to connect to. Here is the code that I am using to build it with AngularJS. I am running the file through a simple Python HTTP Server and viewing it at localhost:8000.
var retrieveAppliances = function () {
console.log('Attempting to retrieve appliance list.');
var requestUrl = '****';
$http({
method: 'GET',
url: requestUrl,
})
.then(function (response) {
console.log(response);
});
};
retrieveAppliances();
I have read multiple places to try switching the method to JSONP but doing so resulted in a parsing error.
While I have considered trying to build a server.js file and running NodeJS with it, I am unsuccessful in learning the basics of making an AJAX request and proxying that to my app.js.
I will greatly appreciate any help that someone may be able to give me, with clear and easy to follow steps.
If you're running an Ajax call to a different origin (e.g. different host, port or protocol) and the server at that origin does not have support for cross origin requests, then you cannot fix that from your client. There is nothing you can do from the client.
If the server supported JSONP, you could use that, but that also requires specific server support.
The only solutions from a browser web page are:
CORS support on the target server.
JSONP (also requires support on the target server).
Set up your own server that you do have access to (either on your existing page domain or with CORS) and then have that server get the file/data for you and proxy it back to you. You can either write your own proxy or deploy a pre-built proxy.
Find some existing third party proxy service that you can use.
If you're interested in making your own node.js proxy, you can see a simple example here: How to create a simple http proxy in node.js?.
I'm getting this error when I try to use $.get on a non-secure site (ie. http, not https):
jquery.min.js:4 Mixed Content: The page at '...' was loaded over HTTPS, but requested an insecure script 'http://api.openweathermap.org/data/2.5/weather?lat=50&lon=2?callback=jQuery...'. This request has been blocked; the content must be served over HTTPS.
I've been trying to think of work-around solutions to this. The problem is a fixed one, since the server is hosted by OpenWeather.org and it's a non-secure site (ie. http, not https).
This is my request code:
$.get("https://api.openweathermap.org/data/2.5/weather?lat=" + latitude + "&lon=" + longitude + "&APPID=123456", function(data) {
tempC = data.weather.main.temp / 10; // OpenWeather API returns Celsius * 10
rain = data.rain["3h"];
clouds = data.clouds.all;
});
Simply changing the request URL to https://api.openweathermap.org... doesn't work, of course. Tried it and didn't work.
The only solution I can think of right now is to find another weather API that is free to use for my project, but I'd like to know if there's a way to still use OpenWeathermap's API, given that it's http. Curious to know this because it seems quite wasteful to have to dismiss certain APIs just because it's http and not https.
Found another post on SO about the same "mixed content" issue. It's helpful and points to many other resources to solve the problem.
The asker ended up dropping openweathermap API (because it's served over HTTP) and using forecast.io's API instead (served over HTTPS while still free).
Using Open Weather Map which is HTTP only through an HTTPS website and NOT get mixed content warning
so, the Problem is, that you run your code on a HTTPS site(JSFiddle and Coodepen). Your browser will not allow HTTP-Connections on a HTTPS site for security-reasons. You can solve that issue by either forcing HTTP on the page where you run your code(try to run a code from a local file or localhost) or you could create a HTTPS -> HTTP forwarding on your server, that would receive a HTTPS request from your code and send a HTTP-request to API.
I would suggest first try to run from a localhost or local file(not sure if every browser will allow AJAX from a local file, but you can try before setting up localhost), that should work for you. If you just want to test the API you can simple copy the URL of the GET-request into you browser tab and execute it.
my server is running over https, but I need to be able to access a resource on an external site (that I have no control over) that is only available via http
I've used the user $resource setup
var tableDefintion = $resource('http://www.externalsite.org/xx/info.php',
{
param: '#data'
}
but, obviously, when I make a resource request I get the dreaded "Mixed Content" message and it will not load
I have tried adding $sceDelegateProvider.resourceUrlWhitelist to the angular config function, but that has made no difference, even when set to ['**']
This resource is being used from within a service - is there anything else I can do to get round this issue ?
thanks
If you are trying to do this by getting the client (browser) to do this request then there is no way round this (MDN) as it's a security risk. However if you have a server why not proxy the request via your server so you can do the TLS termination yourself?
In my javacript function I call this ajax. It works fine but only when I access the web page from firebird server. I have the same code on my testing server. The ajax asks to download some files but only firebird server has its ip registers with our clients to be able to scp there. I need to do the same if I access the php files from testing server. All the servers are inside intranet.
is it possbile to use dataType text to do so?
do I need to do any changes on the server side?
ajax call:
url = "https://firebird"+path+"/tools.php?";
jQuery.ajax({
type: 'get',
dataType: 'text',
url: url,
data: {database: database_name, what: 'download', files: files, t: Math.random() },
success: function(data, textStatus){
document.getElementById("downloading").innerHTML+=data;
}
});
Update 1
My little web application restores databases so I can do my testing on them. Now I want to enhance it so I can connect to our customers and download a particular backup. Our customer allowed only firebird server to connect to their networks. But I have my own server dedicated to testing. So every time I want to download a database I need to connect firebird. The source of my web application and the folder with all backups are mounted into the same location on both servers firebird and testing. Right now my solution (for downloading) works but only from firebird. I work basically only testing server though.
Update 2
I make two ajax calls. One is pure jQuery call (I guess I can apply any solution to this one) and the other one is ajax call from jsTree. I created new question for that one. I seems to me that I have to go for #zzzz's option b).
To do cross domain requests, your options are fairly limited. As #Mrchief mentioned, you could do server side proxy and jsonp.
Another option is Cross-Origin Resource Sharing (CORS), a W3C working draft. Quoting from this blog post:
The basic idea behind CORS is to use custom HTTP headers to allow both
the browser and the server to know enough about each other to
determine if the request or response should succeed or fail.
For a simple request, one that uses either GET or POST with no custom
headers and whose body is text/plain, the request is sent with an
extra header called Origin. The Origin header contains the origin
(protocol, domain name, and port) of the requesting page so that the
server can easily determine whether or not it should serve a response.
You can find some live examples on this site.
You will need to make changes to the server side, to accept the CORS requests. Since you have control over the server, this shouldn't be a problem. Another downside with CORS is that, it might not be compatible with older browsers. So, if some of your essential audiences use incompatible browsers, the server side proxy may actually be a better option for you.
I just want to offer an alternative.
I am not too sure regarding your network setup, but if you have access to the DNS, maybe it would be easiest if you just give your servers some arbitrary subdomain of the same domain. Something like www.foo.com for the webfront and firebird.private.foo.com for the firebird server. This way, it becomes cross subdomain instead of cross domain. Then somewhere in your JavaScript on both pages,
document.domain = "foo.com";
This gentleman achieved this solution here.
You have the following options with you
a) You use jsonp type as your datatype but this involves making changes on the server side to pass the data back as json and not as txt.. this change might be as simple as
{
"text":<your current text json encoded>
}
and on your js side you use this as response.text; Having said that if you are getting the textis for you file from sm other domain I am not sure how easy it is for you to change the code.
b) The other option is you write a handler/end point on your server i.e within your domain that will make an HTTP request to this third domain gets the file and you send the file back to your client and effectively now your client talks to your domain only and you have control over everything. as most of yoyr questions are based on ruby here is an example:
req = Net::HTTP.get_response(URI.parse('http://www.domain.com/coupons.txt'))
#play = req.body
you can find more details about the same here.
Hope this helps.
Another idea is to use you web server as a proxy. You will need to consider the security implications for this route.