AngularJS / Alfresco / CORS 过滤器问题:没有“Access-Control-Allow-Origin”标头

Posted

技术标签:

【中文标题】AngularJS / Alfresco / CORS 过滤器问题:没有“Access-Control-Allow-Origin”标头【英文标题】:AngularJS / Alfresco / CORS filter issue: No 'Access-Control-Allow-Origin' header 【发布时间】:2015-11-06 00:46:53 【问题描述】:

我的 Alfresco (5.0.d)、我的 AngularJS (1.4.3) 客户端CORS 设置(典型跨域/No'Access-Control-Allow-Origin'标头出现在请求的资源上问题)。

我正在从在 localhost:3000 上运行的 AngularJS 应用程序调用 Alfresco REST API 到在 localhost:8080 上运行的 Alfresco 实例(Tomcat,没有反向代理前面)。

这个 XHR 调用工作正常:

http://localhost:8080/alfresco/service/slingshot/live-search-docs?t=Project&u=admin&pw=admin&alf_ticket=TICKET_9d9780c83b8b9525c7acb9d3d8da66c5c902fb76

这个

http://localhost:8080/alfresco/service/api/login?u=admin&pw=admin

仅在 Internet Explorer 11 中工作正常,但在 Chrome 和 Firefox 中,我得到状态代码 200 返回 0 字节和 JS 控制台中的错误:

XMLHttpRequest 无法加载 http://localhost:8080/alfresco/service/api/login?u=admin&pw=admin。不 'Access-Control-Allow-Origin' 标头出现在请求的 资源。因此不允许使用原点“http://localhost:3000” 访问。

在 Alfresco web.xml 中,我启用了 CORS 过滤器,如下所示:

   <!-- CORS Filter Mappings Begin -->
   <filter-mapping>
      <filter-name>CORS</filter-name>
      <url-pattern>/api/*</url-pattern>
      <url-pattern>/service/*</url-pattern>
      <url-pattern>/s/*</url-pattern>
      <url-pattern>/cmisbrowser/*</url-pattern>
   </filter-mapping>
   <!-- CORS Filter Mappings End -->

   <!-- CORS Filter Begin -->
   <filter>
      <filter-name>CORS</filter-name>
      <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
      <init-param>
         <param-name>cors.allowGenericHttpRequests</param-name>
         <param-value>true</param-value>
      </init-param>
      <init-param>
         <param-name>cors.allowOrigin</param-name>
         <!-- <param-value>http://localhost:3000 http://localhost:8081 http://localhost:8080 https://localhost</param-value> -->
         <param-value>*</param-value>
      </init-param>
      <init-param>
         <param-name>cors.allowSubdomains</param-name>
         <param-value>true</param-value>
      </init-param>
      <init-param>
         <param-name>cors.supportedMethods</param-name>
         <param-value>GET, HEAD, POST, PUT, DELETE, OPTIONS</param-value>
      </init-param>
      <init-param>
         <param-name>cors.supportedHeaders</param-name>
         <param-value>origin, authorization, x-file-size, x-file-name, content-type, accept, x-file-type</param-value>
      </init-param>
      <init-param>
         <param-name>cors.supportsCredentials</param-name>
         <param-value>true</param-value>
      </init-param>
      <init-param>
         <param-name>cors.maxAge</param-name>
         <param-value>3600</param-value>
      </init-param>
   </filter>-->
   <!-- CORS Filter End -->

Angular 内部的调用:

运行良好的那个:

$http.get('http://localhost:8080/alfresco/service/slingshot/live-search-docs?t=Project&alf_ticket=TICKET_9d9780c83b8b9525c7acb9d3d8da66c5c902fb76').then(function(response) 
    console.log('DATA LOADED: ' + response.items);
    $scope.contents = response.items;
);

响应标头:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 85
Date: Thu, 13 Aug 2015 06:37:24 GMT

失败者:

$http.get('http://localhost:8080/alfresco/service/api/login?u=' + $scope.user.email + '&pw=' + $scope.user.password).
      then(function(response) 
        console.log('ALF_TICKET: ' + response.data.ticket);
        $scope.alfTicket = response.data.ticket;
        $state.go('admin-panel.default.introduction');
      , function(response) 
        console.log('LOGIN FAILED');
      );

响应标头:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 13 Aug 2015 06:38:36 GMT

我在 AngularJS 应用程序中配置了 $httpProvider,以确保:

.config(['$httpProvider', function($httpProvider) 
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    

从不同主机模拟的 CURL 请求工作正常,但有趣的是,尽管启用了 CORS 过滤器,但我没有在响应中返回 Access-Control-Allow-Origin 标头露天:

curl -H "Origin: http://www.microsoft.com" --verbose "http://alfresco.mycompany.ch:8080/alfresco/service/api/login?u=admin&pw=12@echo"

* Hostname was NOT found in DNS cache
*   Trying 10.10.0.183...
* Connected to alfresco.mycompany.ch (10.10.0.183) port 8080 (#0)
> GET /alfresco/service/api/login?u=admin&pw=12@echo HTTP/1.1
> User-Agent: curl/7.37.1
> Host: alfresco.mycompany.ch:8080
> Accept: */*
> Origin: http://www.microsoft.com
> 
< HTTP/1.1 200 OK
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Cache-Control: no-cache
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Content-Type: application/json;charset=UTF-8
< Content-Length: 85
< Date: Thu, 13 Aug 2015 08:11:15 GMT
< 

   "data":
   
"ticket":"TICKET_7d07634afbb25a7e823c0348d907e0790eeff97e"
   

* Connection #0 to host alfresco.mycompany.ch left intact

因此我认为它与客户端/AngularJS 相关。

=== 更新 1:===

我尝试如下向 $httpProvider 添加一个拦截器,但它没有帮助。尽管调用了拦截器,但我没有在任何响应中看到我设置的标头。

    $httpProvider.interceptors.push(function() 
      return 
       'request': function(request) 
           return request;
        ,
        'response': function(response) 
           console.log('Interceptor called.');
           response.config.headers['MyTestHeader'] = '12345';
           response.config.headers['Access-Control-Allow-Origin'] = '*';
           return response;
        
      ;
    );

=== 更新 2:===

还有一些发现,但现在在 Alfresco 方面有点奇怪。我正在对以下两个 url 进行两个几乎相似的 API 调用:

http://localhost:8080/alfresco/service/api/login http://localhost:8080/alfresco/service/api/whatever

您可以看到,它们仅在最后有所不同。带有/whatever 的那个返回一个Access-Control-Allow-Origin 响应头,带有/login 的那个没有。应该是和Alfresco config / webscript有关,但是我还没找到它的出处。

curl -H "Origin: http://www.microsoft.com" --verbose "http://localhost:8080/alfresco/service/api/login"

*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /alfresco/service/api/login HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://www.microsoft.com
>
< HTTP/1.1 400 Bad Request
< Server: Apache-Coyote/1.1
< Cache-Control: no-cache
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 13 Aug 2015 12:49:46 GMT
< Connection: close
<

但是这个:

curl -H "Origin: http://www.microsoft.com" --verbose "http://localhost:8080/alfresco/service/api/whatever"

*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /alfresco/service/api/whatever HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://www.microsoft.com
>
< HTTP/1.1 404 Not Found
< Server: Apache-Coyote/1.1
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: http://www.microsoft.com
< Vary: Origin
< Cache-Control: no-cache
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Content-Type: text/html;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 13 Aug 2015 12:52:15 GMT
<

我也尝试了Tomcat的CORS过滤器,结果相同。

<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>

问题:

(1) 我在客户端/AngularJS $http 端遗漏了什么吗?我应该使用 angular-http-interceptor 吗? (对不起,AngularJS 很新)。我认为这很可能是这里的原因,但不确定缺少什么。

(2) 我不明白为什么 CORS 过滤器不会将“Access-Control-Allow-Origin”标头添加到两个响应中,而只会添加到一个 API 调用中,因为两个 API url 都以 /alfresco/service 开头,应该由 CORS 过滤器按照&lt;url-pattern&gt;/service/*&lt;/url-pattern&gt; 处理

(为什么它对一个 API url 有效,但对另一个无效?我看到的唯一区别是,在一种情况下,我已经通过身份验证并使用 alf_ticket,在另一种情况下我不是。但是即使我在登录调用中添加(不必要的)alf_ticket,也没有任何区别。)

(3) 那为什么它在 IE 中可以工作呢? (顺便说一句:使用 Chrome 扩展程序 https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi 它也可以在 Chrome 中使用。)

相关SO问题:cross domain call using REST Alfresco

【问题讨论】:

【参考方案1】:

我有同样的问题,由于某种原因,登录 api “GET”调用不会在标题中返回“Access-Control-Allow-Origin”。解决方法:“POST”调用工作正常!

【讨论】:

但这实际上是一个很好的提示,我从来没有关注过 POST 方法,登录 API 也接受 POST。我会试一试。我还没有弄清楚 GET 出现上述问题的原因,我什至已经检查了 Alfresco 源代码。【参考方案2】:

我遇到了类似的问题,并通过使用“/alfresco/s/”而不是“/alfresco/service/”来解决。

在你的情况下,尝试使用

http://localhost:8080/alfresco/s/api/login?u=admin&pw=admin.

试试这是否可行。

【讨论】:

我很想知道我们是否可以使用共享代理进行跨域请求。这行得通吗??意思是,我正在尝试使用hostname:port/share/proxy/alfresco/api....但是我得到 XMLHttpRequest cannot load hostname:port/share/proxy/alfresco/api/people/VGARGNE/…。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此不允许访问 Origin 'localhost:8080'。 对我不起作用。并且这两种 url 模式实际上都包含在 CORS 过滤器映射中。对我有用的只是从 GET 方法切换到 POST 方法。

以上是关于AngularJS / Alfresco / CORS 过滤器问题:没有“Access-Control-Allow-Origin”标头的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 alfresco sdk 中的 alfresco webscripts 中的 CORS 错误?

无法在 Alfresco 中禁用创建站点权限

Alfresco:如何在 Alfresco Share 中搜索链接(app:filelink 或 cm:link 类型的节点)?

Alfresco 和 drupal 集成

在Alfresco中启用JavaScript登录

Alfresco:按名称查询内容