I have a static web angular project in IntelliJ IDEA. The static page gets deployed to http://localhost:63342/Calculator/app/index.html. I have run into a problem where I try to post some data to a server to get a response back but when I try to post I get this error:
XMLHttpRequest cannot load <url>. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 401.
Here is my post angular code:
WebIdServer.prototype.getId = function(id) {
var _this = this;
var request = {
method: 'POST',
url: 'https://<url>,
headers: {
'Authorization':'Bearer QWE234J234JNSDFMNNKWENSN2M3',
'Content-Type':'application/json',
},
data: {
id:id
}
};
_this.$log.debug(request);
return _this.$http(request)
.success(function(data, status, headers, config){
_this.$log.debug("Successfull request.");
/*called for result & error because 200 status*/
_this.uid = data.id;
_this.$log.debug(_this.uid);
})
.error(function(data, status, headers, config){
_this.$log.debug("Something went wrong with the request.");
_this.$log.debug(data);
/*handle non 200 statuses*/
});
};
I know for a fact that post works because I tried it on a local url of my application that I had running on a different port.
So my question is, since I can't post from localhost I was wondering if maybe deploying this to a tomcat server would fix things. If so, how do you deploy this static web project to a tomcat server? If that's not necessary, then how do I get around this problem I'm having?
There's a few things regarding CORS. It's a web browser telling you you cannot make a particular call. This is only a front end problem, a script running on a server can call any api regardless of the location. Three different options:
without config; same hosts
Without any configuration on your server, your front end's AJAX requests need to match both the domain and the port of the service you're calling. In your case, your angular app at http://localhost:63342 should be calling a service also hosted on http://localhost:63342 and then you're sweet. No CORS issues.
with server side config; different hosts
If the API is hosted elsewhere, you'll have to configure the API host. Most servers will let you configure access controls, to allow a particular domain to bypass the CORS block. If you have access to the server you're trying to call, see if you can set it up. The enable CORS website has examples for most servers. Usually this is pretty simple.
Create a proxy
This is your Tomcat idea. CORS is only a problem if your front end calls another service. A server script can call anything it likes. So, you could use Tomcat (or Apache, or NGINX, or NodeJS...) to host a script that'll pass on the request. Essentially, all it needs to do is add Access-Control-Allow-Origin: * to the response of the API.
I have never used Tomcat myself, but here's a blog post that might have some useful info on how to do that. Combine it with the info on enable CORS and you should be able to route anything to anywhere.
This process is common. Just look at the popularity of a node package like CORS anywhere, which is what your tomcat does.
As a disclaimer, how good of an idea this is depends on how you can pass along the credentials and tokens. You don't really want to create a service that'll just blindly call someone else's API with your credentials.
Related
hope you can help me with this.
I am developing an application using Angular 8, that calls some Java REST Services (not a Spring backend, the services are written using only Jersey). When developing backend services, i used Postman app to test them, and this took me to an error: it seems that Postman automatically manages JSESSIONID, so when i try to call my service in Angular application, i realised that i have to do it manually.
The real question is, how to manage that ID in Angular? When i call my first service, a login service, in "Network" session of Chrome console i can see in response's headers the field:
Set-Cookie: JSESSIONID=averylongstring
I tried, following different other questions, to get it with
response.headers.get('Set-Cookie')
but it returns null. If i write
console.log(response.headers)
in .subscribe method, i can't see any relevant header, picture is following:
How can I access to that id? Is an error in Angular response handling or in service? I tried to return first a custom serializable bean and then a javax.ws.rs.core.Response object, hoping to fix, but i get the same situation.
Sometimes, mostly while responding to authentication/authorization request, the server uses "Set-Cookie" to set an "Http-Only" cookie for JSESSIONID to prevent XSS exploits, or so.
In these cases, you cannot read/get JSESSIONID cookie from client side, even if you see it on your browser's console.
We use ngx-cookie-service for managing cookies in our Angular applications. Here is how you can set it up:
npm install ngx-cookie-service --save
or
yarn add ngx-cookie-service
Add the cookie service to your app.module.ts as a provider:
import { CookieService } from 'ngx-cookie-service';
#NgModule({
...
providers: [ CookieService ],
...
})
export class AppModule { }
Then, import and inject it into a constructor:
constructor( private cookieService: CookieService ) {
this.cookieValue = this.cookieService.get('JSESSIONID');
}
Alternatively you can just access document.cookie but that would be much less explicit.
Seems like there is a lot of CORS stuff on here. A million ways to handle it.
Converting over an app to Ionic. Because of WKWebView
This seems to run the code as local host on the ios. Which in tern means I need to handle CORS.
Followed this example.
https://amodernstory.com/2014/12/27/using-cors-headers-with-java-example/
At this point its just the web.xml has the CorsFilter setup. (defaults)
I thought I was going to have to do something in the code, but nothing I have added seems to make any difference.
What happens, is I login, and I trace that through and that seems to work fine.
Then the code pulls the users profile info. This is a seperate web service call.
That is getting blocked.
polyfills.js:3 POST [webserviceURL]/user/getUser 403 (Forbidden)
(index):1 Failed to load [webserviceURL]/user/getUser:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:8100' is therefore not allowed access.
The response had HTTP status code 403.
The first call to login goes through. The second call never hits the web server.
Not sure why. Maybe I need to tell it to remember the Origin?
Try adding proxy URLs:
From Handling CORS issues in Ionic:
Set up your ionic.project file to be something like:
{
"name": "proxy-example",
"app_id": "",
"proxies": [
{
"path": "/api",
"proxyUrl": "http://cors.api.com/api"
}
]
}
You have to add following in your web services header:
Access-Control-Allow-Origin: http://localhost:8100
Also, You can use ionic native http plugin to resolve cors issue.
I have used this in our projects successfully to resolve cors issue.
Here is the link of this plugin: https://ionicframework.com/docs/native/http/
The server sending JSON to the API is a Tomcat server in the Gradle packages (it is built in Java).
I am having trouble's making an API call with Angular. I know my API is working because I can view it on "Postman."
var app = angular.module("todo", []);
app.controller("AppCtrl", function($http){
$http.get("192.168.5.100:8080/aggregators/datafile")
.success(function(data){
console.log(data)
})
})
When I run it I get the following error:
XMLHttpRequest cannot load %3192.168.5.100:8080/aggregators/datafile. Cross origin requests are only supported for HTTP.
The problem you're running into is that you can't make cross origin requests from the browser without CORS or using JSONP.
Postman operates outside of the context of the browser (as if you had issued a cURL request, if you're familiar with cURL).
This is for security reasons.
So, how do you implement JSONP? It really depends on the server, but in general, your resource would look for a GET request that had a pre-determined querystring parameter (normally callback for simplicity):
http://192.168.5.100:8080/aggregators/datafile?callback=mycallback
How do you make a JSONP call?
The server wraps the JSON in that callback, causing it to look something like the following:
mycallback({json:object});
This Stack Overflow answer goes into more detail.
The callback is the function the browser should hit when the request is executed, and that's what allows for cross-domain requests.
Now, on to CORS.
CORS is a system for allowing the browser to communicate with the server to determine whether or not it should accept a cross domain request. It's a bit complicated, but in general it involves settings up certain Headers on your API Server; and then executing an Ajax request in a particular fashion (for JQuery, use the withCredentials property for $.ajax). The server checks where the request is from, and if it's a valid source, it let's the browser know and the browser allows the request (I'm being simplistic).
MDN has a thorough explanation of CORS that is worth reading.
I am trying to make a JQuery $.post to a Java Servlet. I integrated the Tomcat server into
Apache and if the Tomcat server is on the same machine as the Apache the $.post succeded.
(The Java Servlet receives it).
If the Tomcat servlet is on a remote machine and if I make $.post(http://ip:8080/App/MyServlet,...) the servlet doesn't receive anything.
If I make a JQuery $.post on my machine I have like this $.post(Myservlet,.....).
If I try like this : $.post(http://localhost:8080/App/MyServlet,...) it doesn't work.
How should I make a JQuery $.post to a remote uri?
How should the remote uri for a Tomcat Servlet look like?
Thanks,
Jquery runs in the browser (client-side), which means it's subject to the browser's same-origin policy, which is a good thing.
This means ajax requests that are GET or POST can only be made to the domain of the page making the ajax request.
There are 2 ways to bypass the policy. The first is to have the remote server vouch for the request, the second is to sneak around the browser's same-origin policy.
So if you have control over the remote server, or if the admin who does takes requests to open the server/domain to foriegn ajax requests, then the server just needs to send the following header:
Access-Control-Allow-Origin: your-local-domain.org
The browser gets back the response header, sees that the requesting page is in the above list, and allows the response through.
If you have no control over the remote server, here are the sneakier ways to get around same-origin policy:
Make an ajax request to a local url with the parameters, and have it pass it along to the servlet, and the have that proxy script return whatever the servlet responds with.
JSONP (which I'm still fuzzy on, honestly, but jquery's ajax documentation goes into it)
Script injection, where you leverage the fact that the script element's src is not limited by the same-origin policy.
Of the 3, I think the first is the safest, least hackish, and most honest (so to speak), but JSONP has become the simple and easy way to pull of a cross-domain request in jquery.
I'm currently using Play! 1.2.2 and its new Netty client framework.
I haven't found a straightforward method to enforce SSL, although can get HTTP and HTTPS to serve asynchronously. Does anyone that's worked with Play! have a straightforward method of enforcing SSL? Not sure if I need to create redirects or if this can be solved quickly in a conf file.
There are a couple of ways to enforce SSL.
Firstly, you can set all your actions to use the .secure() method, for example
index page
Alternatively, and probably the best way, is to do this via a frontend HTTP server, such as Apache, Nginx or Lighttpd.
The idea of the frontend http server, is that your application runs on port 9000, but is not accessible from the outside network. HTTP is responsible for all incoming requests, and is configured to only accept HTTPS. The HTTPS is handled by the HTTP server, and the request is then forwarded on to Play.
This leaves your entire Play application to work as normal, and the SSL is offloaded to another application.
This same method can be applied to a load balancer, rather than HTTP server, but I am guessing the majority of people will go with the far cheaper alternative of a HTTP server, unless running in a corporate environment.
In the controller you can check against request.secure and either do a redirect or return 403/access denied.
You can force SSL for a whole controller doing this:
public static class ForceSSL extends Controller
{
#Before
static void verifySSL()
{
if (request.secure == false)
redirect("https://" + request.host + request.url);
}
}
... and annotate another controller:
#With(ForceSSL.class)
public class Foo extends Controller
{
....
}
See also http://groups.google.com/group/play-framework/browse_thread/thread/7b9aa36be85d0f7b