The problem
Every time I call some services which are on different machine from one which served the application using $http
or $resource
services I end up with following error:
This is CORS. Shortly you just not allowed to call some other service from client side JS due to security reason.
Solutions
The most common solution is to use JSONP approach.
Another solution is to enable CORS on external service. If you lucky enough to be able to change it and if it’s a Spring Boot application you can use this approach: Enabling Cross Origin Requests for a RESTful Web Service which basically add an @CrossOrigin
annotation to the method which enables cross-origin requests for annotated method.
I haven’t tried first solution. Second worked quite good but unfortunately we used quite many services and it became unmanagable.
The solution
Since it’s possible to call only the server which served the application I decided to create a proxy controller which basically redirects all the requests to the proper service, and then simply returns the response back.
So instead of calling someservice.com/getUsers
I call local controller at localhost:8080/proxy/someservice/getUsers
which then calls someservice.com/getUsers
and simply returns the response. Here is simple implementation of proxy controller for two POST methods:
In case of calling many services all urls could be put in a map and then it would be just one method:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HashMap<String, String> redirects = new HashMap<String, String>(){
{
put("person/acl", "/access-rights/person/acl");
put("read/acl/document/all", "/access-rights/document/acl/all");
put("read/acl/document", "/access-rights/document/acl");
put("read/access", "/access-rights/permission");
}
};
@RequestMapping(value = "/proxy/dar/**", method = RequestMethod.POST)
public String genericProxyPost(RequestEntity<String> requestEntity, HttpServletRequest request) throws
URISyntaxException
{
String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
String path = new AntPathMatcher().extractPathWithinPattern(pattern, request.getServletPath());
return getResponseBody("http://external-service.com" + redirects.get(path), requestEntity, HttpMethod.POST);
}
For the code above all requests which starts with /proxy/dar/
will endup in this method (line 10).
The key in the map is local path, the value is path of the external service.
Then in path
variable would be written the remaining part of the URL, which is key in the map (line 15).
By this key we take the part of URL from the map of external service and redirect HTTP call there (line 17).
Basically the code above tells redirect calls from http://localhost:8080/proxy/dar/person/acl
to http://external-service.com/access-rights/person/acl
and so on according to the map.