While developing REST web service, we came across an error “No ‘Access-Control-Allow-Origin’ header is present on the requested resource” with Http Status code 403, after exploring more on it, found the details of CORS and how browser supports it. Obviously as a user (mostly developer) I can disable the security and can make the request, but lets understand the ideal way of handling it.
What is CORS?
This document defines a mechanism to enable client-side cross-origin requests. Specifications that enable an API to make cross-origin requests to resources can use the algorithms defined by this specification. If such an API is used on
http://example.org resources, a resource on
http://hello-world.example can opt in using the mechanism described by this specification (e.g., specifying
Access-Control-Allow-Origin: http://example.org as response header), which would allow that resource to be fetched cross-origin from
You can find more details on : http://www.w3.org/TR/cors/
So if you are making request to same server but the URL is different, the request will be treated as the cross-domain, e.g. http://localhost and http://184.108.40.206 will be treated as the cross-domain. Specification is implemented by the browser to support same-origin policy and security. When browser makes a request, it check for the origin and the URL of the request made to, if it wont match (protocol+domain+port number should be same) then a pre-flight request is made to the server, which is nothing but a same request with HTTP method OPTION. e.g. if you are making a call from localhost:8080/app/index.html to 127.0.0.1:8080/app/hello then request is made to 127.0.0.1:8080/app/hello with OPTION http method.
OPTIONS /app/home HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Access-Control-Request-Method: GET Origin: http://localhost:8080 Access-Control-Request-Headers: accept, content-type Accept: */* Referer: http://localhost:8080/app/index.html
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://localhost:8080 Access-Control-Allow-Credentials: true Access-Control-Max-Age: 1800 Access-Control-Allow-Methods: GET Access-Control-Allow-Headers: content-type,access-control-request-headers,access-control-request-method,accept,origin,x-requested-with Content-Length: 0
If your server returns the Access-Control-Allow-Origin headers then only client can access the targeted site content, when the preflight request is successful then browser makes the original request. Once the request is successful, browser cache the details of the origin, url (request made to), max-age and header details, so for subsequent requests to same URL will be served directly and in that case preflight request will be not sent.
On Server Side, How I can support the cross-site request
We do use Tomcat, from Tomact version 7.0.40 by default CorsFilter is included, you just need to enable it for your application, the minimal configuration is
<filter> <filter-name>CorsFilter</filter-name> <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>CorsFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
you can specify the optional parameters by adding init parameters, follow this link for more details.
<init-param> <param-name>cors.allowed.origins</param-name> <param-value>http://localhost:8080, http://127.0.0.1:8080</param-value> </init-param> <init-param> <param-name>cors.allowed.methods</param-name> <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value> </init-param>
If you have Apache or any other HTTP server between client and you application server, then make sure you have implemented cross-site support on those servers.
if your application is used or open for limited applications, it is recommended to use specific domain names list for “Allowed Origin”, if you have a global web API then you can use *.
More on OPTION method
This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval. Mostly option do not have the body, but specification is open and in future option body may be supported to make detailed query on server.
BTW : WebSocket won’t fall under same-origin or cross-site policy, so if you create a WebSocket to different URL it will work.