YAWS、CORS:如何定义 OPTIONS 应该 return?

YAWS, CORS: How to define what OPTIONS should return?

我需要让 CORS 工作。似乎 jquery $ajax 进行了 OPTIONS 调用,这应该 return 必要的 CORS headers。我所有的 GET 和 POST 都已经这样做了,但似乎还不够。在 NGINX 中,你会做这样的事情:

location / {
    if ($request_method = OPTIONS ) {
        add_header Access-Control-Allow-Origin "http://example.com";
        add_header Access-Control-Allow-Methods "GET, OPTIONS";
        add_header Access-Control-Allow-Headers "Authorization";
        add_header Access-Control-Allow-Credentials "true";
        add_header Content-Length 0;
        add_header Content-Type text/plain;
        return 200;
    }
}

如何在 YAWS 中执行相同的操作?

处理 OPTIONS 请求的一种方法是使用 Yaws dispatchmod,它类似于 Yaws appmod,但 Yaws 在做任何其他请求处理。这是一个基于您问题中的信息的示例调度模块:

-module(options_dispatcher).
-export([dispatch/1]).

-include_lib("yaws_api.hrl").

dispatch(Arg) ->
    Req = yaws_api:arg_req(Arg),
    case yaws_api:http_request_method(Req) of
        'OPTIONS' ->
            Vsn = yaws_api:http_request_version(Req),
            Resp = #http_response{
                      version=Vsn,
                      status=200,
                      phrase=yaws_api:code_to_phrase(200)},
            HdrVals = [{"Access-Control-Allow-Origin", "http://example.com"},
                       {"Access-Control-Allow-Methods", "GET, OPTIONS"},
                       {"Access-Control-Allow-Headers", "Authorization"},
                       {"Access-Control-Allow-Credentials", "true"},
                       {"Content-Length", "0"},
                       {"Content-Type", "text/plain"}],
            Headers = lists:foldl(fun({H,V}, Hdrs) ->
                                          yaws_api:set_header(Hdrs, H, V)
                                  end, #headers{}, HdrVals),
            HdrStrings = yaws_api:reformat_header(Headers),
            Reply = [yaws_api:reformat_response(Resp), "\r\n",
                     string:join(HdrStrings, "\r\n"), "\r\n\r\n"],
            Sock = yaws_api:arg_clisock(Arg),
            case yaws_api:get_sslsocket(Sock) of
                {ok, SslSock} ->
                    ssl:send(SslSock, Reply);
                undefined ->
                    gen_tcp:send(Sock, Reply)
            end,
            done;
        _ ->
            continue
    end.

此代码接收 Yaws #arg{} 记录,与 appmod 相同,但注意 dispatchmod 必须导出 dispatch/1 函数,而 appmod 必须导出 out/1 函数。它从那里检索请求信息并检查 HTTP 请求方法。如果是 OPTIONS,代码会创建一个响应记录并设置响应 headers,将它们格式化为字符串,然后创建 Reply 值,该值是一个 iolist,其中包含HTTP 响应状态行,格式化的 HTTP 响应 headers,以及 "\r\n\r\n" 来标记 HTTP 响应的结束。然后它根据收到请求的套接字类型使用 ssl:send/2gen_tcp:send/2 直接发送回复。最后它 returns done 告诉 Yaws 对于该请求没有更多的工作要做。对于 OPTIONS 以外的任何 HTTP 方法,代码 returns continue 告诉 Yaws 执行其正常调度。

要部署调度程序,请编译代码并将生成的光束文件放在 Yaws 加载路径中。然后修改 Yaws 配置的服务器部分以包含设置:

dispatchmod = options_dispatcher

这告诉 Yaws 服务器有一个 dispatchmod 应该作为该服务器的请求调度流的一部分被调用。然后 start/restart Yaws 或使用

yaws --hup --id ID

告诉 运行 Yaws 实例重新加载其配置。