fix api_handler

This commit is contained in:
anlicheng 2024-09-10 15:59:19 +08:00
parent c8e4497a20
commit ac6ea78aa4
6 changed files with 100 additions and 104 deletions

View File

@ -10,22 +10,74 @@
-author("licheng5"). -author("licheng5").
%% API %% API
-export([handle_request/4]). -export([init/2]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init(Req0, Opts) ->
%% helper methods 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, ReqBody, Req1} = parse_body(Req0),
Sign = cowboy_req:header(<<"sign">>, Req1, <<>>),
case njau_bot_signer:sign(ReqBody) =:= Sign of
true ->
{ok, StatusCode, Resp} = handle_request(Method, Path, GetParams, ReqBody),
lager:debug("[http_protocol] request path: ~p, get_params: ~p, post_params: ~p, response: ~ts",
[Path, GetParams, ReqBody, Resp]),
Req2 = cowboy_req:reply(StatusCode, #{
<<"Content-Type">> => <<"application/json">>
}, Resp, Req1),
{ok, Req2, Opts};
false ->
Req2 = cowboy_req:reply(500, #{
<<"Content-Type">> => <<"text/html;charset=utf-8">>
}, <<"Internal Server Error">>, Req1),
{ok, Req2, Opts}
end.
handle_request("POST", "/api/device_info", _, Params) -> handle_request("POST", "/api/device_info", _, Params) ->
njau_bot_logger:write(jiffy:encode(Params, [force_utf8])), njau_bot_logger:write(jiffy:encode(Params, [force_utf8])),
{ok, 200, http_protocol:json_data(<<"hello world">>)}; {ok, 200, json_data(<<"hello world">>)};
handle_request(_, Path, _, _) -> handle_request(_, Path, _, _) ->
Path1 = list_to_binary(Path), Path1 = list_to_binary(Path),
{ok, 200, http_protocol:json_error(-1, <<"url: ", Path1/binary, " not found">>)}. {ok, 200, json_error(-1, <<"url: ", Path1/binary, " not found">>)}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% helper methods %% helper methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
parse_body(Req0) ->
ContentType = cowboy_req:header(<<"content-type">>, Req0),
case ContentType of
<<"application/json", _/binary>> ->
{ok, Body, Req1} = read_body(Req0),
{ok, Body, 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.
json_data(Data) ->
Json = jiffy:encode(#{<<"result">> => Data}, [force_utf8]),
iolist_to_binary(Json).
json_error(ErrCode, ErrMessage) when is_integer(ErrCode), is_binary(ErrMessage) ->
jiffy:encode(#{
<<"error">> => #{
<<"code">> => ErrCode,
<<"message">> => ErrMessage
}
}, [force_utf8]).

View File

@ -1,96 +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]).
-export([json_data/1, json_error/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 = 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.
json_data(Data) ->
Json = jiffy:encode(#{<<"result">> => Data}, [force_utf8]),
iolist_to_binary(Json).
json_error(ErrCode, ErrMessage) when is_integer(ErrCode), is_binary(ErrMessage) ->
jiffy:encode(#{
<<"error">> => #{
<<"code">> => ErrCode,
<<"message">> => ErrMessage
}
}, [force_utf8]).

View File

@ -35,7 +35,7 @@ start_http_server() ->
Dispatcher = cowboy_router:compile([ Dispatcher = cowboy_router:compile([
{'_', [ {'_', [
{"/api/[...]", http_protocol, [api_handler]} {"/api/[...]", api_handler, []}
]} ]}
]), ]),

View File

@ -0,0 +1,28 @@
%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2024, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 10. 9 2024 15:08
%%%-------------------------------------------------------------------
-module(njau_bot_signer).
-author("anlicheng").
%% API
-export([sign/1]).
%%
-spec sign(S :: binary()) -> binary().
sign(S) when is_binary(S) ->
{ok, Token} = application:get_env(njau_bot, token),
md5(iolist_to_binary([Token, S, Token])).
-spec md5(Str :: binary()) -> binary().
md5(Str) when is_binary(Str) ->
list_to_binary(lists:flatten([hex(X) || <<X:4>> <= erlang:md5(Str)])).
hex(N) when N < 10 ->
$0 + N;
hex(N) ->
$a + (N - 10).

View File

@ -6,7 +6,9 @@
{acceptors, 500}, {acceptors, 500},
{max_connections, 10240}, {max_connections, 10240},
{backlog, 10240} {backlog, 10240}
]} ]},
{token, "aB3$dEfGhiJkLmNoPqRsTuVwXyZ!@#4f5e6d7c8b9a0f1e2d"}
]}, ]},
%% 系统日志配置系统日志为lager, 支持日志按日期自动分割 %% 系统日志配置系统日志为lager, 支持日志按日期自动分割

10
docs/Sign.md Normal file
View File

@ -0,0 +1,10 @@
# 签名算法的说明
## 约定token的值为
aB3$dEfGhiJkLmNoPqRsTuVwXyZ!@#4f5e6d7c8b9a0f1e2d
## 所有接口调用都必须传递签名值,签名值算法如下:
参数签名算法,算法逻辑如下:
1. 将对象转换成JSON字符串str1
2. 将str1进行和给定的token值进行拼接后然后对字符串进行md5加密, 格式如何: md5_str = md5($token + str1 + $token)
3. md5_str放到post请求的header里面格式如下: sign: md5_str