У меня возникла проблема с Alfresco (5.0.d), моим клиентом AngularJS (1.4.3) и настройками CORS (обычно междоменный / заголовок No'Access-Control-Allow-Origin' присутствует в запрошенном ресурсе проблема).
Я вызываю REST API Alfresco из приложения AngularJS, работающего на локальном хосте: 3000, в экземпляр Alfresco, работающий на локальном хосте: 8080 (Tomcat, без обратного прокси-сервера впереди) .
Этот вызов XHR отлично работает:
Этот
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
У меня настроен $httpProvider в моем приложении AngularJS, просто чтобы быть уверенным:
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
Запрос CURL, смоделированный с другого хоста, работает нормально, однако интересно то, что я не получаю заголовок Access-Control-Allow-Origin
в ответе, несмотря на включенный фильтр CORS в Alfresco:
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. Я делаю два почти одинаковых вызова API для следующих двух URL-адресов:
- http://localhost:8080/alfresco/service/api/login
- http://localhost:8080/alfresco/service/api/whatever
Как видите, они отличаются только в конце. Тот, у кого /whatever
, возвращает заголовок ответа Access-Control-Allow-Origin
, тот, у кого /login
, нет. Это должно быть связано с конфигом/веб-скриптом Alfresco, но я пока не нашел его происхождение.
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
<
Я также попробовал фильтр CORS Tomcat, тот же результат.
<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, поскольку оба URL-адреса API начинаются с /alfresco/service, что должно обрабатываться фильтром CORS согласно <url-pattern>/service/*</url-pattern>
(И почему для одного URL API работает, а для другого нет? Единственное отличие, которое я вижу, это то, что в одном случае я уже аутентифицирован и использую alf_ticket, а в другом — нет. Но даже если я добавьте (ненужный) alf_ticket к вызову входа в систему, это не имеет никакого значения.)
(3) Почему тогда он вообще работает в IE? (кстати: с расширением Chrome https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi, он также работает в Chrome.)
Связанный вопрос SO: междоменный вызов с использованием REST Alfresco