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

Posted

技术标签:

【中文标题】Access-Control-Allow-Origin 不允许使用 Origin - 如何使用非常简单的 Web 堆栈和 guice 启用 CORS【英文标题】:Origin is not allowed by Access-Control-Allow-Origin - how to enable CORS using a very simple web stack and guice 【发布时间】:2013-04-27 10:33:58 【问题描述】:

我不确定问题出在所涉及的技术上,还是我对这些技术的理解上。

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

我有一个用 java 编写的 java 应用程序,使用 jetty、guice、jackson、jersey 托管一个简单的 REST 服务。

两个应用程序在同一个机器上运行,一个在端口 80(托管在 apache 上的纯 html5 应用程序),另一个在 8080(托管在 jetty/guice 上的纯 java 应用程序)

我相信答案就在我发回的标题中。 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);
    

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

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

感谢您的建议。

【问题讨论】:

Why am I seeing an "origin is not allowed by Access-Control-Allow-Origin" error here? 的可能重复项 我的问题是服务器端,示例处理客户端。客户端库已经处理了这些不一致。这是一个基于服务器的问题。 已添加,因为我使用带有 guice 的嵌入式码头服务器。我不确定如何在没有 web.xml 的情况下进行配置......我知道它缺乏对技术的理解。但我觉得这个问题中的技术堆栈与可能的重复项有足够的不同,因为它涉及到一个非常不同的技术堆栈,因此值得自己关注。 调用者和被调用者在同一个盒子上,只是在不同的端口上。并且正在使用两个不同的服务器堆栈......我知道 cors 是答案。我只是在如何实现它方面遗漏了一些东西,或者我对自己在做什么感到完全困惑。 【参考方案1】:

满足我的应用程序的具体要求。服务器需要与客户端完全分开。客户端应该能够通过任何方法连接到通信服务器。

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

此外,我想要一个完全没有 xml 的配置,所以我使用带有嵌入式 Jetty 服务器的 Guice。由于我没有 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 应用程序与它对话,无论它在哪里提供服务。

【讨论】:

这很有帮助。我试图将过滤器添加到 Jetty,但后来意识到我需要使用 Guice ServletModule。我不得不在接受的标题中添加“授权”,但其他一切都有效。谢谢!【参考方案2】:

只需在代码文件中添加一行

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

如果您只想允许特定域使用,请将 * 替换为您的 http://www.yoursite.com

【讨论】:

【参考方案3】:

将此添加到您的 httpServletResponse 在 java 端,即在服务器端代码将解决问题。

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

【讨论】:

以上是关于Access-Control-Allow-Origin 不允许使用 Origin - 如何使用非常简单的 Web 堆栈和 guice 启用 CORS的主要内容,如果未能解决你的问题,请参考以下文章

PHP没有按顺序执行

跨域请求被阻止 Symfony/AngularJS

C# MVC js 跨域

PHP Ajax 跨域问题最佳解决方案

PHP Ajax 跨域问题最佳解决方案

PHP Ajax 跨域问题最佳解决方案