【问题标题】:Enabling CORS for Cowboy REST API为 Cowboy REST API 启用 CORS
【发布时间】:2013-03-15 00:09:06
【问题描述】:

如何为牛仔休息处理程序启用 CORS? 我尝试添加 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...

我的错误在哪里?

【问题讨论】:

    标签: rest erlang cors cowboy


    【解决方案1】:

    Cowboy 文档说您需要使用 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
    

    【讨论】:

    • options/2 应该在哪里实现?文档并不清楚我们应该在哪个文件中实现它。
    【解决方案2】:

    我的 REST 仅在提供令牌的情况下才允许访问资源。所以我必须实现is_authorized/2 回调,这对于 OPTIONS 和 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}.
    

    【讨论】:

      【解决方案3】:

      你可以试试这个:

      Req1 = cowboy_req:set_resp_header(<<"access-control-allow-origin">>, <<"*">>, Req0 -> Worked for me.
      

      【讨论】:

      • 这个问题已有 6.5 年历史,具有高质量的公认答案。此提供的答案被标记为低质量帖子以供审核。以下是How do I write a good answer? 的一些指南。提供的这个答案可能是正确的,但它可以从解释中受益。仅代码答案不被视为“好”答案。来自review
      【解决方案4】:

      除了这里找到的答案之外,Cowboy 2.* 似乎还有一个中间件功能,您可以使用它来拦截对服务器的所有 REST 处理程序请求,并添加所需的响应标头: https://ninenines.eu/docs/en/cowboy/2.7/guide/middlewares/

      可以在这个 Github gist 中找到一个示例 CORS 中间件实现: https://github.com/ninenines/cowboy/blob/master/examples/markdown_middleware/src/markdown_middleware_app.erl

      【讨论】:

        猜你喜欢
        • 2012-12-26
        • 1970-01-01
        • 2016-02-17
        • 2015-11-09
        • 2018-03-23
        • 2017-03-05
        • 2014-09-13
        • 2019-04-17
        • 2017-12-16
        相关资源
        最近更新 更多