Включение CORS для Cowboy REST API
Как включить CORS для обработчика Cowboy rest? Я попытался добавить метод options / 2, например:
options(Req, State) ->
{[
{<<"access-control-allow-origin">>, <<"*">>},
{<<"access-control-allow-methods">>, <<"GET, OPTIONS">>}
], Req, State}.
но это вызывает такие ошибки, как:
Error in process <0.263.0> with exit value: {{case_clause,{[{<<27 bytes>>,<<1 byte>>},{<<28 bytes>>,<<12 bytes>>}],{http_req,#Port<0.2636>,ranch_tcp,keepalive,<0.263.0>,<<7 bytes>>,{1,1},{{127,0,0,1},56522},<<9 bytes>>,undefined,9090,<<8 bytes>>,undefined,<<0 bytes>>,undefined,<<0 bytes>>,[],[{<<4 bytes>>,<<14 bytes>>},{<<10 bytes>>,<<74 bytes>>},{<<6 bytes>>,<<63 bytes>>},{<<15 bytes>>,<<14 bytes>>},{<<15 bytes>>,<<13 bytes>>},{<<6 bytes>>,<<4 bytes>>},{<<29 bytes>>,<<3 bytes>>},{<<30 bytes>>,<<16 bytes>>},{<<10 bytes>>,<<10 bytes>>}],[{<<10 bytes>>,[<<10 bytes>>]}],undefined,[],waiting,undefined,<<0 bytes>>,false,waiting,[],<<0 bytes>>,undefined},undefined...
где моя ошибка?
2 ответов
в документации ковбоя говорится, что вам нужно установить заголовок с помощью set_resp_headers, а не возвращать список заголовков:
%% If you need to add additional headers to the response at this point,
%% you should do it directly in the options/2 call using set_resp_headers.
Так что ваш код должен выглядеть так:
options(Req, State) ->
Req1 = cowboy_req:set_resp_header(<<"access-control-allow-methods">>, <<"GET, OPTIONS">>, Req),
Req2 = cowboy_req:set_resp_header(<<"access-control-allow-origin">>, <<"*">>, Req1),
{ok, Req2, State}.
вы можете проверить с
curl -H "Origin: http://example.com" \
-H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS --verbose \
http://localhost:8080
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8080 (#0)
> OPTIONS / HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:8080
> Accept: */*
> Origin: http://example.com
> Access-Control-Request-Method: GET
> Access-Control-Request-Headers: X-Requested-With
>
< HTTP/1.1 200 OK
< connection: keep-alive
< server: Cowboy
< date: Mon, 25 Mar 2013 15:59:11 GMT
< content-length: 0
< access-control-allow-methods: GET, OPTIONS
< access-control-allow-origin: *
<
* Connection #0 to host localhost left intact
* Closing connection #0
My REST разрешает доступ только к ресурсам и только если предоставляется токен. Поэтому мне пришлось реализовать is_authorized/2
обратный вызов, который отличается для опций и запросов GET. См. ниже:
1) реализовать options/2
следующим образом
options(Req0, State) ->
% cors
Req1 = cowboy_req:set_resp_header(
<<"access-control-allow-methods">>, <<"GET, OPTIONS">>, Req0),
Req2 = cowboy_req:set_resp_header(
<<"access-control-allow-origin">>, <<"*">>, Req1),
Req3 = cowboy_req:set_resp_header(
<<"access-control-allow-headers">>, <<"authorization">>, Req2),
{ok, Req3, State}.
2) реализовать is_authorized/2
следующим образом
is_authorized(Req, State) ->
case cowboy_req:method(Req) of
<<"GET">> ->
case cowboy_req:parse_header(<<"authorization">>, Req) of
{bearer, <<Token/binary>>} ->
{true, Req, Token};
_ ->
{{false, <<"Basic realm=\"cowboy\"">>}, Req, State}
end;
<<"OPTIONS">> ->
{true, Req, State}
end.
3) to_json/2
способ отправки access-control-allow-origin
to_json(Req0, State) ->
R = #{ foo => [<<"bar">>] },
% cors
Req1 = cowboy_req:set_resp_header(
<<"access-control-allow-origin">>, <<"*">>, Req0),
Body = jsx:encode(R),
{Body, Req1, State}.