%%%------------------------------------------------------------------- %%% @author anlicheng %%% @copyright (C) 2025, %%% @doc %%% %%% @end %%% Created : 08. 5月 2025 13:00 %%%------------------------------------------------------------------- -module(http_protocol). -author("anlicheng"). %% API -export([init/2]). 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), try Mod:handle_request(Method, Path, GetParams, PostParams) of {ok, StatusCode, Resp} -> lager:debug("[http_protocol] request path: ~p, get_params: ~p, post_params: ~p, response: ~ts", [Path, GetParams, PostParams, 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 -> ErrResp = iot_util:json_error(-1, Error), Req2 = cowboy_req:reply(404, #{ <<"Content-Type">> => <<"application/json;charset=utf-8">> }, ErrResp, Req1), {ok, Req2, Opts}; _:Error:Stack -> lager:warning("[http_handler] get error: ~p, stack: ~p", [Error, Stack]), Req2 = cowboy_req:reply(500, #{ <<"Content-Type">> => <<"text/html;charset=utf-8">> }, <<"Internal Server Error">>, 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 jiffy:decode(Body, [return_maps]), 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, <>, Req1}; {more, Data, Req1} -> read_body(Req1, <>) end.