Origin is not allowed by Access-Control-Allow-Origin - how to enable CORS using a very simple web stack and guice
Asked Answered
K

3

12

I am not sure if the issue is the technologies involved, or my understanding of the technologies.

I have an html5 application written in javascript and html hosted on an apache 2.2 server.

I have a java application written in java using jetty, guice, jackson, jersey that hosts a simple REST service.

Both applications run on the same box, one on port 80 (pure html5 application hosted on apache), the other on 8080 (pure java application hosted on jetty/guice)

I believe the answer is in the headers im sending back. The CORS headers tell a browser that you allow outside applications to hit your api. I cannot seem to figure out how to configure my Jetty, Guice server to return the correct CORS headers.

I am using an imbeded Jetty server so I do not have a web.xml file to add the headers with.

It also might be something to do with how the HTML5 application server (in this case apache 2.2) is serving the application.

The apache httpd.conf file has the entry:

LoadModule headers_module modules/mod_headers.so

<IFModule mod_headers>
    Header add Access-Control-Allow-Origin "*"
    Header add Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE, HEAD
    Header add Access-Control-Allow-Headers: X-PINGOTHER
    Header add Access-Control-Max-Age: 1728000  
</IfModule>

in my guice servlet configuration I have the following:

public class RestModule extends ServletModule{

    @Override
    protected void configureServlets() {
        bind(QuestbookService.class);

        // hook Jersey into Guice Servlet
        bind(GuiceContainer.class);

        // hook Jackson into Jersey as the POJO <-> JSON mapper
        bind(JacksonJsonProvider.class).in(Scopes.SINGLETON);

        Map<String, String> guiceContainerConfig = new HashMap<String, String>();
        guiceContainerConfig.put(ResourceConfig.PROPERTY_RESOURCE_FILTER_FACTORIES,
            HttpStatusCodeMetricResourceFilterFactory.class.getCanonicalName());
        serve("/*").with(GuiceContainer.class, guiceContainerConfig);
    }
}

I think the problem is in my guice config since I don't have a place to set the response headers.

I am using an embedded jetty server and thus I figured dev mode would bypass the whole check, but I could be wrong.

Thank you for any advice.

Kinser answered 3/5, 2013 at 4:56 Comment(4)
possible duplicate of Why am I seeing an "origin is not allowed by Access-Control-Allow-Origin" error here?Adonis
My question is server side, the example deals with the client side. The client side library already takes care of these inconsistancies. It is a server based issue.Kinser
Added, since im using an embedded jetty server with guice. I am unsure how to configure without web.xml... I know its a lack of understanding of the technologies. but I feel that the technology stack in this question is different enough from the possible duplicate that it warrants its own attention since it involves a very different technology stack.Kinser
The caller and the callee are on the same box, just on different ports.. And are using two different server stacks... I know cors is the answer. I am just either missing something on how to implement it, or I am totally confused as to what I am doing.Kinser
K
18

Do to the specific requirements of my application. The server needs to be seporate completly seporate from the client. The client should be able to connect to the communication server via any method it can.

Since the first implementation of this application is going to be REST driven, I need to be able to accept rest from anywhere.

In addition, I want a completly xml-less config, so I use Guice with an imbedded Jetty server. Since I do not have a web.xml file, I could not figure out how to set the headers to allow CORS.

After alot of trial and error, and reading the guice documentation, I found how to add the CORS headers to the response leaving the server.

The Guice ServletModule class allows you to add filters to your servlet context. This allows me to have all requests pass through a given servlet.

Since I am trying to build a rest application that responds to CORS requests, i needed a filter that added the cors headers to the response of any request.

So to enable cors in my embedded server using guice I built a filter that looks like this:

@Singleton
public class CorsFilter implements Filter{

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain filterChain) throws IOException, ServletException {

        if(response instanceof HttpServletResponse){
        HttpServletResponse alteredResponse = ((HttpServletResponse)response);
        addCorsHeader(alteredResponse);
    }

    filterChain.doFilter(request, response);
    }

    private void addCorsHeader(HttpServletResponse response){
        //TODO: externalize the Allow-Origin
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
        response.addHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");
        response.addHeader("Access-Control-Max-Age", "1728000");
    }

    @Override
    public void destroy() {}

    @Override
    public void init(FilterConfig filterConfig)throws ServletException{}
}

Guice provides an abstract class that allows you to configure the Guice Servlet.

The configuration module looks like this:

public class RestModule extends ServletModule{

    @Override
    protected void configureServlets() {
        bind(MyServiceClass.class);

        // hook Jersey into Guice Servlet
        bind(GuiceContainer.class);

        // hook Jackson into Jersey as the POJO <-> JSON mapper
        bind(JacksonJsonProvider.class).in(Scopes.SINGLETON);

        Map<String, String> guiceContainerConfig = new HashMap<String, String>();

        serve("/*").with(GuiceContainer.class, guiceContainerConfig);

        filter("/*").through(CorsFilter.class);
    }
}

Now guice will add cors headers to every response. Allowing my pure HTML 5 application to talk to it, no matter where it is being served.

Kinser answered 5/5, 2013 at 1:16 Comment(1)
This was very helpful. I was trying to add the filter into Jetty, but then realized I needed to use the Guice ServletModule. I had to add 'Authorization' to the accepted headers, but everything else worked. Thanks!Agenda
F
7

Just put one line in your code file

response.addHeader("Access-Control-Allow-Origin", "*");

Replace * with your http://www.yoursite.com if you want to allow only for particular domain

Floorer answered 24/7, 2014 at 7:13 Comment(0)
H
0

Adding this to your httpServletResponse at java side i.e. at server side code will fix the issue.

 httpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
 httpServletResponse.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
 httpServletResponse.addHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");
 httpServletResponse.addHeader("Access-Control-Max-Age", "1728000");
Humphrey answered 27/7, 2019 at 9:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.