2016-07-21 2 views
6

При отладке проблемы CORS, с которой я столкнулся, я нашел следующее поведение. Хром делает следующие опции предполетного запроса (переписан в CURL самой Chrome):Запрос предварительной проверки CORS из-за стандартного заголовка

curl -v 'https://www.example.com/api/v1/users' -X OPTIONS -H 'Access-Control-Request-Method: POST' -H 'Origin: http://example.com' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Accept-Language: es-ES,es;q=0.8,en;q=0.6' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36' -H 'Accept: */*' -H 'Referer: http://example.com/users/new' -H 'Connection: keep-alive' -H 'Access-Control-Request-Headers: accept, x-api-key, content-type' 

ответ от сервера на этот запрос, если следующий:

< HTTP/1.1 403 Forbidden 
< Date: Thu, 21 Jul 2016 14:16:56 GMT 
* Server Apache/2.4.7 (Ubuntu) is not blacklisted 
< Server: Apache/2.4.7 (Ubuntu) 
< X-Content-Type-Options: nosniff 
< X-XSS-Protection: 1; mode=block 
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate 
< Pragma: no-cache 
< Expires: 0 
< Strict-Transport-Security: max-age=31536000 ; includeSubDomains 
< X-Frame-Options: SAMEORIGIN 
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH 
< Content-Length: 20 
< Keep-Alive: timeout=5, max=100 
< Connection: Keep-Alive 

является телом ответа «Invalid Запрос CORS '. Если бы я повторить запрос удаления заголовка «Access-Control-Request-Method» (и только то, что заголовок) Опции запросов преуспевает со следующим réponse:

< HTTP/1.1 200 OK 
< Date: Thu, 21 Jul 2016 14:21:27 GMT 
* Server Apache/2.4.7 (Ubuntu) is not blacklisted 
< Server: Apache/2.4.7 (Ubuntu) 
< X-Content-Type-Options: nosniff 
< X-XSS-Protection: 1; mode=block 
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate 
< Pragma: no-cache 
< Expires: 0 
< Strict-Transport-Security: max-age=31536000 ; includeSubDomains 
< X-Frame-Options: SAMEORIGIN 
< Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with, x-api-key 
< Access-Control-Max-Age: 60 
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS 
< Access-Control-Allow-Origin: * 
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH 
< Content-Length: 0 
< Keep-Alive: timeout=5, max=100 
< Connection: Keep-Alive 

Однако заголовок нарушитель является CORS spec standard header так оно должно не препятствовать выполнению запроса, не так ли? Почему этот заголовок вызывает такое поведение?

И как я могу настроить заголовки управления доступом, отправленные моим сервером, чтобы заставить запрос работать при работе с Chrome?

Кстати, я использую Chrome 36.0, а сервер использует Spring Boot, а заголовки CORS управляются Spring.

Когда запрос сделан Firefox (v47.0), поведение отличается от аналогового результата. Firefox даже не отправляет запрос предварительной проверки, он напрямую отправляет запрос POST, который получает в качестве ответа 403 Forbidden. Однако, если я копирую запрос с параметром «Копировать как cURL» и повторяю его из окна терминала, он успешно завершает работу и отправляет правильные заголовки CORS в ответ.

Любая идея?

Обновление: Firefox отправляет запрос опций предварительной проверки (как показано в плагине Live HTTP headers), но Firebug маскирует его, поэтому поведение в обоих браузерах одинаково. В обоих браузерах есть заголовок «Access-control-request-method», разница, которая делает запрос неудачным.

ответ

14

После многих проблем, я, наконец, нашел проблему. Я настроил отображение запроса в Spring для обработки OPTIONS трафика, например:

@RequestMapping(value= "/api/**", method=RequestMethod.OPTIONS) 
public void corsHeaders(HttpServletResponse response) { 
    response.addHeader("Access-Control-Allow-Origin", "*"); 
    response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 
    response.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with"); 
    response.addHeader("Access-Control-Max-Age", "3600"); 
} 

Я не знал, что по умолчанию Spring использует default CORS processor, и кажется, что это было вмешательство с моим отображением запроса. Удаление моего запроса и добавление аннотации @CrossOrigin к соответствующим сопоставлениям запросов позволило решить проблему.

+2

Да, что голова поездки, Spring имеет процессор Корс по умолчанию, но если его не настроен, он actuall y прерывает нормальную обработку CORS, если у вас есть настройка в Apache. Похоже, вам нужно настроить CorsFilter или следовать рекомендациям здесь - https://spring.io/guides/gs/rest-service-cors/ – chrismarx

+1

Я нашел это сообщение полезным также: http://stackoverflow.com/вопросы/9521690/как-к-ручке-HTTP-опции-с-весна-Mvc DispatchServlet должен быть сконфигурирован для передачи по запросу опций, или же она никогда не достигает отображенный запрос: ... < имя-сервлет> YourServlet <сервлет-класс> org.springframework.web.servlet.DispatcherServlet dispatchOptionsRequest true 1 ... – Mike

0

Я добавил это в качестве ответа, потому что я не мог отформатировать его для голосового ответа.

Я нашел этот пост полезным, а также: How to handle HTTP OPTIONS with Spring MVC?

DispatchServlet должен быть сконфигурирован для передачи по запросу опций, или же она никогда не достигает отображенный запрос:

... 
    <servlet> 
    <servlet-name>yourServlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>dispatchOptionsRequest</param-name> 
     <param-value>true</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
    </servlet> 
... 
0

Я была такая же проблема. Я разрешаю это, добавляя «ОПЦИИ» к разрешенным методам CORS в моей конфигурации Spring MVC.

@Configuration 
@EnableWebMvc 
@ComponentScan 
public class RestApiServletConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void addCorsMappings(CorsRegistry registry) { 
     super.addCorsMappings(registry); 
     registry.addMapping("/**") 
       .allowedOrigins("http://localhost:3000", "http://localhost:8080") 
       .allowedMethods("GET", "PUT", "POST", "DELETE", "OPTIONS"); 
    } 
} 
0

я также столкнулся с теми же проблемами и найти решение для обеспечения глобальной проблемы Корса весной ботинке

@Configuration 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 
    @Override 
    public void addCorsMappings(CorsRegistry registry) { 
     registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*") 
       .allowedHeaders("*"); 
    } 
} 

после этого, нам нужно включить CORS в уровне безопасности пружинной также, так что для этого оного CORS() в вашем классе SecurityConfiguration какой степени WebSecurityConfigurerAdapter

@Override 
    protected void configure(HttpSecurity httpSecurity) throws Exception { 

     httpSecurity 
       .cors() 
       .and() 
       .csrf().disable() 
       .authorizeRequests().. 

    }