simple http

This commit is contained in:
anlicheng 2025-05-19 11:00:55 +08:00
parent f1869445b2
commit c62a8bd0e1
2 changed files with 73 additions and 85 deletions

View File

@ -1,82 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author licheng5
%%% @copyright (C) 2020, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 26. 4 2020 3:36
%%%-------------------------------------------------------------------
-module(http_protocol).
-author("licheng5").
%% 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),
{ok, catch jiffy:decode(Body, [return_maps]), Req1};
<<"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.

View File

@ -11,6 +11,7 @@
%% API
-export([start/0]).
-export([init/2]).
%% http服务
start() ->
@ -22,8 +23,8 @@ start() ->
Dispatcher = cowboy_router:compile([
{'_', [
{"/host/[...]", http_protocol, [host_handler]},
{"/device/[...]", http_protocol, [device_handler]}
{"/host/[...]", ?MODULE, [host_handler]},
{"/device/[...]", ?MODULE, [device_handler]}
]}
]),
@ -36,4 +37,73 @@ start() ->
{ok, Pid} = cowboy:start_clear(http_listener, TransOpts, #{env => #{dispatch => Dispatcher}}),
lager:debug("[iot_app] the http server start at: ~p, pid is: ~p", [Port, Pid]).
lager:debug("[iot_app] the http server start at: ~p, pid is: ~p", [Port, Pid]).
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),
{ok, catch jiffy:decode(Body, [return_maps]), Req1};
<<"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.