CORS - Como fazer um 'preflight' de um httprequest?

94

Estou tentando fazer uma solicitação HTTP de domínio cruzado para o serviço WCF (de minha propriedade). Eu li várias técnicas para trabalhar com as limitações de script entre domínios. Como meu serviço deve acomodar solicitações GET e POST, não posso implementar alguma tag de script dinâmico cujo src é a URL de uma solicitação GET. Como estou livre para fazer alterações no servidor, comecei a tentar implementar uma solução alternativa que envolve a configuração das respostas do servidor para incluir o cabeçalho "Access-Control-Allow-Origin" e solicitações de 'comprovação' com uma solicitação OPTIONS. Tive a ideia deste post: Fazendo o CORS funcionar

No lado do servidor, meu método da web está adicionando 'Access-Control-Allow-Origin: *' à resposta HTTP. Posso ver que as respostas incluem este cabeçalho agora. Minha pergunta é: Como faço para 'comprovar' uma solicitação (OPÇÕES)? Estou usando jQuery.getJSON para fazer a solicitação GET, mas o navegador cancela a solicitação imediatamente com o infame:

Origem http: // localhost não é permitido por Access-Control-Allow-Origin

Alguém está familiarizado com essa técnica CORS? Que mudanças precisam ser feitas no cliente para comprovar minha solicitação?

Obrigado!

usuario
fonte

Respostas:

158

Durante a solicitação de comprovação, você deve ver os dois cabeçalhos a seguir: Access-Control-Request-Method e Access-Control-Request-Headers. Esses cabeçalhos de solicitação estão solicitando ao servidor permissões para fazer a solicitação real. Sua resposta de comprovação precisa reconhecer esses cabeçalhos para que a solicitação real funcione.

Por exemplo, suponha que o navegador faça uma solicitação com os seguintes cabeçalhos:

Origin: http://yourdomain.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header

Seu servidor deve então responder com os seguintes cabeçalhos:

Access-Control-Allow-Origin: http://yourdomain.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: X-Custom-Header

Preste atenção especial ao cabeçalho de resposta Access-Control-Allow-Headers. O valor desse cabeçalho deve ser o mesmo cabeçalho do pedido Access-Control-Request-Headers e não pode ser '*'.

Depois de enviar essa resposta à solicitação de comprovação, o navegador fará a solicitação real. Você pode aprender mais sobre CORS aqui: http://www.html5rocks.com/en/tutorials/cors/

monsur
fonte
você poderia adicionar vários domínios ao Access-Control-Allow-Origin?
botbot
@botbot Você provavelmente já resolveu isso agora, mas caso outros estejam se perguntando, podem fazerAccess-Control-Allow-Origin: *
Steve Chambers
2
Possivelmente perdi algo. Portanto, devo enviar duas solicitações XMLHttp? Um para o pré-vôo; verificar a resposta em caso de sucesso e enviar a consulta real?
Kangkan
14
@Kangkan, você não precisa se preocupar em enviar a solicitação de comprovação. Se a solicitação precisar de um preflight, o navegador enviará para você.
Monsur
4
OBRIGADO pela parte 'preste atenção especial' ... que resolveu meu problema com node / expressjs. Consegui adicionar um filtro para capturar essas solicitações de pré-voo//cors and preflight filtering app.all('*', function(req, res, next){.. //preflight needs to return exact request-header res.set('Access-Control-Allow-Headers', req.headers['access-control-request-headers']); if ('OPTIONS' == req.method) return res.send(204);next(); });
Kurtfm
0

Embora essa discussão remonte a 2014, o problema ainda pode ser atual para muitos de nós. Aqui está como eu lidei com isso em um contexto jQuery 1.12 / PHP 5.6:

  • jQuery enviou sua solicitação XHR usando apenas cabeçalhos limitados; apenas 'Origem' foi enviada.
  • Nenhuma solicitação de comprovação foi necessária.
  • O servidor só tinha que detectar essa solicitação e adicionar o "Access-Control-Allow-Origin:". $ _SERVER ['HTTP_ORIGIN'] cabeçalho, após detectar que este era um XHR de origem cruzada.

Amostra de código PHP:

if (!empty($_SERVER['HTTP_ORIGIN'])) {
    // Uh oh, this XHR comes from outer space...
    // Use this opportunity to filter out referers that shouldn't be allowed to see this request
    if (!preg_match('@\.partner\.domain\.net$@'))
        die("End of the road if you're not my business partner.");

    // otherwise oblige
    header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
}
else {
    // local request, no need to send a specific header for CORS
}

Em particular, não adicione um, exit;pois nenhum preflight é necessário.

Fabien Haddadi
fonte