【问题标题】:How to use CORS in Restlet 2.3.1?如何在 Restlet 2.3.1 中使用 CORS?
【发布时间】:2015-04-14 07:25:56
【问题描述】:

我正在尝试为响应设置“Access-Control-Allow-Origin: *”标头。但是,标题不存在。我究竟做错了什么?

public class JsonApplication extends Application
{
    private static final String SERVER_URL = "http://localhost:8111";

    public static void main(String[] args) throws Exception 
    {
        Server testServer = new Server(Protocol.HTTP, 8111);        
        JsonApplication jsonApplication = new JsonApplication();

        CorsService corsService = new CorsService();         
        corsService.setAllowedOrigins( new HashSet(Arrays.asList("*")));
        corsService.setAllowedCredentials(true);

        jsonApplication.getServices().add( corsService );      

        testServer.setNext( jsonApplication );
        testServer.start();
    }

    @Override
    public Restlet createInboundRoot()
    {
        Router router = new Router( getContext() );
        router.attach( SERVER_URL + "/", RootResource.class );        
        return router;
    }
}

我检查了 org.restlet.engine.application.CorsResponseHelper 的源代码,它包含以下代码:

public void addCorsResponseHeaders(Request request, Response response) {

String origin = request.getHeaders().getFirstValue("Origin", true);

if (origin == null) {
    // Not a CORS request
    return;
}
...
}

因此,当前的 CORS 实现似乎不支持从本地 html 文件发出的请求,因为在这种情况下 origin == null。

我在我的 servlet 应用程序中添加了一些日志记录:

JsonApplication::createInboundRoot()
16:26 MyCorsService()
16:26 myCorsService = wwwdbase.rest.cors.MyCorsService@6e1b241d
16:26 MyCorsService::setAllowedOrigins(), [*]
16:26 services: [org.restlet.service.TunnelService@4c88fe62, 
org.restlet.service.StatusService@68349a5b,
org.restlet.service.DecoderService@77cfd8d3,
org.restlet.service.EncoderService@40c331fb,
org.restlet.service.RangeService@4bb3bc6f,
org.restlet.service.ConnectorService@7990100,
org.restlet.service.ConnegService@e194860,
org.restlet.service.ConverterService@578cfcb1,
org.restlet.service.MetadataService@18a62eb,
org.restlet.service.TaskService@4ed4f2db,
wwwdbase.rest.cors.MyCorsService@6e1b241d]

我们可以看到 MyCorsService 可用。但是,servlet 框架永远不会调用它。另一方面,如果我从 IDE 运行服务(Java SE 版本),则会调用 MyCorsService。为什么这些案例表现不同?

部分解决方案:我设法通过更改 org.restlet.engine.header.HeaderUtils 中的代码来添加允许来源标头

if (response.getAccessControlAllowOrigin() != null) 
{          
    addHeader(HeaderConstants.HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
            response.getAccessControlAllowOrigin(), headers);
}

if (response.getAccessControlAllowOrigin() != null) 
{          
    addHeader(HeaderConstants.HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
            response.getAccessControlAllowOrigin(), headers);
}
else
{
    // --- Add in any case!
    //           
    response.setAccessControlAllowOrigin( "*" );
    addHeader(HeaderConstants.HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
                    response.getAccessControlAllowOrigin(), headers);            
}

但是,关于Tomcat中的servlet框架为什么没有调用cors服务的问题,这个问题的答案还是个未知数……

【问题讨论】:

    标签: cors restlet


    【解决方案1】:

    其实你已经正确配置了Restlet的CORS服务;-)

    在CORS的上下文中,有两种请求:

    • 简单的请求。简而言之,当您使用方法GETHEADPOST 的某些情况时。在这种情况下,执行跨域请求时不需要 CORS 标头。
    • 预检请求 需要 CORS 标头来执行跨域请求的其他情况。

    所以如果你只是简单地做一个方法GET,你什么也没看到是很正常的。尝试使用带有 JSON 内容的方法 POST,您将看到 CORS 标头。

    更多详情,你可以看看这个链接:

    已编辑

    我对您的问题进行了更完整的测试。我在不同的端口上启动了两个 Restlet 服务器(8182 用于使用 AJAX 访问的资源,8183 用于访问资源的 JS 应用程序)。

    第一个是用你的代码配置的:

    CorsService corsService = new CorsService();         
    corsService.setAllowedOrigins(new HashSet(Arrays.asList("*")));
    corsService.setAllowedCredentials(true);
    
    RestletApplication application = new RestletApplication();
    application.getServices().add(corsService);
    component.getDefaultHost().attachDefault(application);
    

    里面的服务器资源很简单:

    public class MyServerResource extends ServerResource {
        @Get
        public TestBean ping() {
            TestBean bean = new TestBean();
            bean.setMessage("pong");
            return bean;
        }
    }
    

    第二个应用程序仅使用 Restlet 目录来提供静态内容:

    @Override
    public Restlet createInboundRoot() {
        Router router = new Router(getContext());
        router.attach("/static", new Directory(
                getContext(), "clap:///test/static"));
        return router;
    }
    

    除了 JQuery 库之外,我还添加了以下 HTML 文件:

    <html>
      <head>
        <script type="text/javascript" src="/static/jquery-1.11.2.min.js"></script>
        <script type="text/javascript">
        $(document).ready(function() {
          $('#id1').click(function() {
            $.ajax({
               url : 'http://localhost:8182/ping',
               type : 'GET',
               success : function(result, status){
                   console.log('ok = '+result);
               },
               error : function(result, status, error){
                   console.log('error');
               },
               complete : function(result, status){
                    console.log('complete');
               }
            });
          });
        });
        </script>
      </head>
      <body>
        <div id="id1">Click</div>
      </body>
    </html>
    

    这是我在标题级别单击“单击”按钮时所看到的:

    // Request
    Accept  */*
    Accept-Encoding gzip, deflate
    Accept-Language fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
    Host    localhost:8182
    Origin  http://localhost:8183
    Referer http://localhost:8183/static/test.html
    User-Agent  Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:36.0) Gecko/20100101 Firefox/36.0
    
    // Response
    Accept-Ranges   bytes
    Access-Control-Allow-Cred...    true
    Access-Control-Allow-Orig...    http://localhost:8183
    Content-Type    application/json
    Date    Fri, 13 Mar 2015 09:16:48 GMT, Fri, 13 Mar 2015 09:16:48 GMT
    Server  Restlet-Framework/2.3.1
    Transfer-Encoding   chunked
    Vary    Accept-Charset, Accept-Encoding, Accept-Language, Accept
    

    如您所见,CORS 存在 ;-)

    希望对你有帮助 蒂埃里

    【讨论】:

    • 感谢您的回答。我正在开发一个以 JSON 格式返回数据的 RESTful 服务。客户端可以开发自己的基于浏览器的 UI 并使用 AJAX 调用与服务器交互。默认情况下禁止跨域 AJAX 调用,因此即使使用 GET,也需要 CORS(或 JSONP)。但是,我通过直接在浏览器的地址栏中写入请求 url 来测试服务器调用。显然,这不是一个正确的 AJAX 调用,所以难怪标题是否丢失。我隐含假设,如果正确配置了 CORS,Restlet 框架总是包含标头...
    • 我用更完整的测试编辑了我的答案。似乎在 AJAX 请求中,CORS 标头在那里 ;-)
    • 我现在已经在 localhost Tomcat 服务器下安装了我的应用程序。如果我通过 jQuery Ajax 从本地 html 文件调用该服务,我会得到响应:'Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at localhost:8080/rest/authentication.这可以通过将资源移动到同一个域或启用 CORS 来解决。所以,似乎 CORS 不起作用!?
    • 在基于html文件的调用中,有一个请求头'Origin null'。也许这就是问题的根源。如果有,怎么解决?
    • 请编辑此答案,它具有误导性。 “简单请求”还需要 CORS 标头,您链接的博客文章确认了这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-04
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    • 2015-05-10
    • 2016-10-24
    相关资源
    最近更新 更多