91 lines
3.4 KiB
Erlang
91 lines
3.4 KiB
Erlang
%%%-------------------------------------------------------------------
|
|
%%% @author licheng5
|
|
%%% @copyright (C) 2020, <COMPANY>
|
|
%%% @doc
|
|
%%%
|
|
%%% @end
|
|
%%% Created : 26. 4月 2020 3:36 下午
|
|
%%%-------------------------------------------------------------------
|
|
-module(http_protocol).
|
|
-author("licheng5").
|
|
|
|
%% API
|
|
-export([init/2]).
|
|
|
|
-spec init(Req :: cowboy_req:req(), Opts :: [module()]) -> {ok, cowboy_req:req(), [module()]}.
|
|
init(Req0, Opts = [Mod|_]) ->
|
|
Method = binary_to_list(cowboy_req:method(Req0)),
|
|
Path = binary_to_list(cowboy_req:path(Req0)),
|
|
GetParams0 = cowboy_req:parse_qs(Req0),
|
|
GetParams = maps:from_list(GetParams0),
|
|
{ok, PostParams, Req1} = parse_body(Req0),
|
|
|
|
Headers = cowboy_req:headers(Req0),
|
|
logger:debug("[http_protocol] request path: ~p, get_params: ~p, post_params: ~p, headers: ~p",
|
|
[Path, GetParams, PostParams, Headers]),
|
|
|
|
try Mod:handle_request(Method, Path, GetParams, PostParams) of
|
|
{ok, StatusCode, Resp} ->
|
|
AcceptEncoding = cowboy_req:header(<<"accept-encoding">>, Req1, <<>>),
|
|
Req2 = case iolist_size(Resp) >= 1024 andalso supported_gzip(AcceptEncoding) of
|
|
true ->
|
|
Resp1 = zlib:gzip(Resp),
|
|
cowboy_req:reply(StatusCode, #{
|
|
<<"Content-Type">> => <<"application/json;charset=utf-8">>,
|
|
<<"Content-Encoding">> => <<"gzip">>
|
|
}, Resp1, Req1);
|
|
false ->
|
|
cowboy_req:reply(StatusCode, #{
|
|
<<"Content-Type">> => <<"application/json;charset=utf-8">>
|
|
}, Resp, Req1)
|
|
end,
|
|
{ok, Req2, Opts}
|
|
catch
|
|
throw:Error ->
|
|
Req2 = cowboy_req:reply(404, #{
|
|
<<"Content-Type">> => <<"application/json;charset=utf-8">>
|
|
}, Error, Req1),
|
|
{ok, Req2, Opts};
|
|
_:Error:Stack ->
|
|
logger:warning("[http_handler] get error: ~p, stack: ~p", [Error, Stack]),
|
|
ErrorBin = sdlan_util:term_to_binary(Error),
|
|
Req2 = cowboy_req:reply(500, #{
|
|
<<"Content-Type">> => <<"text/html;charset=utf-8">>
|
|
}, <<"Internal Server Error: ", ErrorBin/binary>>, Req1),
|
|
{ok, Req2, Opts}
|
|
end.
|
|
|
|
%% 判断是否支持gzip
|
|
supported_gzip(AcceptEncoding) when is_binary(AcceptEncoding) ->
|
|
binary:match(AcceptEncoding, <<"gzip">>) =/= nomatch.
|
|
|
|
parse_body(Req0) ->
|
|
ContentType = cowboy_req:header(<<"content-type">>, Req0),
|
|
case ContentType of
|
|
<<"application/json", _/binary>> ->
|
|
{ok, Body, Req1} = read_body(Req0),
|
|
case Body /= <<>> of
|
|
true ->
|
|
{ok, catch json:decode(Body), Req1};
|
|
false ->
|
|
{ok, #{}, Req1}
|
|
end;
|
|
<<"application/x-www-form-urlencoded">> ->
|
|
{ok, PostParams0, Req1} = cowboy_req:read_urlencoded_body(Req0),
|
|
PostParams = maps:from_list(PostParams0),
|
|
{ok, PostParams, Req1};
|
|
_ ->
|
|
{ok, #{}, Req0}
|
|
end.
|
|
|
|
%% 读取请求体
|
|
read_body(Req) ->
|
|
read_body(Req, <<>>).
|
|
read_body(Req, AccData) ->
|
|
case cowboy_req:read_body(Req) of
|
|
{ok, Data, Req1} ->
|
|
{ok, <<AccData/binary, Data/binary>>, Req1};
|
|
{more, Data, Req1} ->
|
|
read_body(Req1, <<AccData/binary, Data/binary>>)
|
|
end.
|