fix api_handler
This commit is contained in:
parent
c8e4497a20
commit
ac6ea78aa4
@ -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]).
|
||||||
@ -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]).
|
|
||||||
@ -35,7 +35,7 @@ start_http_server() ->
|
|||||||
|
|
||||||
Dispatcher = cowboy_router:compile([
|
Dispatcher = cowboy_router:compile([
|
||||||
{'_', [
|
{'_', [
|
||||||
{"/api/[...]", http_protocol, [api_handler]}
|
{"/api/[...]", api_handler, []}
|
||||||
]}
|
]}
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
|||||||
28
apps/njau_bot/src/njau_bot_signer.erl
Normal file
28
apps/njau_bot/src/njau_bot_signer.erl
Normal 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).
|
||||||
@ -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
10
docs/Sign.md
Normal 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
|
||||||
Loading…
x
Reference in New Issue
Block a user