2015-02-02 1 views
0

Мне нужно сделать работу CORS. Кажется, что jquery $ ajax вызывает вызов OPTIONS, и он должен возвращать необходимые заголовки CORS. Все мои GET и POST уже делают это, но, похоже, этого недостаточно. В NGINX вы бы сделали примерно следующее:YAWS, CORS: Как определить, какие ВАРИАНТЫ должны возвращаться?

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?

+0

Я вижу код типа «handle (« OPTIONS », A) ->», должен ли я сделать appmod, чтобы перехватывать OPTIONS? Или я могу легко добавить набор заголовков по умолчанию? – mattias

ответ

1

Один из способов справиться с 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, код создает запись ответа и устанавливает заголовки ответов, форматирует их как строки, а затем создает значение Reply, которое представляет собой iolist, содержащее строку состояния ответа HTTP, отформатированные заголовки HTTP-ответа и "\r\n\r\n", чтобы отметить конец HTTP-ответа. Затем он использует либо ssl:send/2, либо gen_tcp:send/2, исходя из того, какой тип сокета получил запрос, чтобы отправить ответ напрямую. Наконец, он возвращает done, чтобы рассказать Yaws, что больше нет работы для этого запроса. Для любого метода HTTP, отличного от OPTIONS, код возвращает continue, чтобы сказать, что Yaws выполняет обычную диспетчеризацию.

Чтобы развернуть диспетчер, скомпилируйте код и поместите полученный файл луча в путь загрузки Yaws. Затем измените серверную часть вашего Yaws конфигурации, чтобы включить параметр:

dispatchmod = options_dispatcher 

Это говорит фрамбезии, что сервер имеет dispatchmod, который должен быть вызван как часть потока отправки запроса на этот сервер. Затем либо запустить/перезапустить торможение, либо использовать

yaws --hup --id ID 

, чтобы сообщить запущенному экземпляру Yaws, чтобы перезагрузить его конфигурацию.

+0

Работает отлично для http, но не для https. Я добавил диспетчер дважды в YAWS 1.98 conf, чуть ниже строки appmods. Получил следующее. Если я удалю строку для https-каталога. Он работает снова. 20: 54: 51,179 [ошибка] Фрамбезия процесс умер: {function_clause, [{prim_inet, setopts, [{s slsocket, {gen_tcp, # Порт <0.7123>, tls_connection, <0.60.0>}, <0.171.0>}, [{пакет, сырье }, {active, false}]], []}, {yaws_server, aloop, 4, [{file, "yaws_server.erl"}, {line, 1188 }]}, {yaws_server, acceptor0,2, [{file, «yaws_server.erl»}, {line, 1052}]}, {proc_lib, i nit_p_do_apply, 3, [{file, "proc_lib.erl"}, {line, 237}]}]} – mattias

+0

Хорошая уловка, это ошибка, теперь зафиксированная на Yaws master. Вы можете увидеть diff здесь: [https://github.com/klacke/yaws/commit/cefd5bc](https://github.com/klacke/yaws/commit/cefd5bc359df9336b965fc7c648976a539790265). –

+0

Да, я обновил YAWS до этой фиксации, и это решает проблему. – mattias