Access-Control-Allow-Origin不允许起源-如何使用非常简单的Web堆栈和guice启用CORS


问题内容

我不确定问题是涉及的技术还是我对技术的理解。

我有一个用javascript和html编写的html5应用程序,托管在apache 2.2服务器上。

我有一个使用Jetty,Guice,Jackson,Jersey用Java编写的Java应用程序,它承载一个简单的REST服务。

这两个应用程序都在同一个盒子上运行,一个在端口80上运行(纯html5应用程序托管在apache上),另一个在8080上运行(纯Java应用程序托管在jetty
/ guice上)。

我相信答案在即时通讯回传的标头中。CORS标头告诉浏览器,您允许外部应用程序访问您的api。我似乎无法弄清楚如何配置我的Jetty,Guice服务器以返回正确的CORS标头。

我使用的是嵌入式Jetty服务器,因此没有web.xml文件可用于添加标头。

这也可能与HTML5应用程序服务器(在本例中为apache 2.2)如何为应用程序提供服务有关。

apache httpd.conf文件具有以下条目:

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>

在我的guice servlet配置中,我具有以下内容:

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);
    }
}

我认为问题出在我的向导配置中,因为我没有地方设置响应头。

我使用的是嵌入式码头服务器,因此我发现开发人员模式会绕过整个检查,但我可能是错的。

感谢您的任何建议。


问题答案:

按照我的应用程序的特定要求进行操作。服务器需要与客户端完全隔离。客户端应该能够通过它可以使用的任何方法连接到通信服务器。

由于此应用程序的第一个实现将由REST驱动,因此我需要能够从任何地方接受休息。

另外,我想要一个完全没有xml的配置,因此我将Guice与嵌入式Jetty服务器一起使用。由于我没有web.xml文件,因此我无法弄清楚如何设置标头以允许CORS。

经过大量的试验和错误,并阅读了guice文档,我发现了如何将CORS标头添加到离开服务器的响应中。

Guice ServletModule类使您可以向Servlet上下文添加过滤器。这使我可以使所有请求都通过给定的servlet。

由于我试图构建一个响应CORS请求的rest应用程序,因此我需要一个过滤器,该过滤器将cors标头添加到任何请求的响应中。

因此,为了使用guice在嵌入式服务器中启用cors,我构建了一个过滤器,如下所示:

@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提供了一个抽象类,允许您配置Guice Servlet。

配置模块如下所示:

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);
    }
}

现在,guice将在每个响应中添加cors标头。无论在哪里提供服务,都允许我的纯HTML 5应用程序与之对话。