0%

ERLANG解决“证书出错,请登录微信支付商户平台下载证书”

解决“证书出错,请登录微信支付商户平台下载证书”的核心代码

1
2
3
4
5
6
7
8
9
10
11
12
request_post(Url, Path, {data, Str}) ->
ReqUrl = lists:concat([Url, Path]),
%% +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
%% 😊这个是核心的核心😊
SSLOptions = [
{keyfile,"apiclient_key.pem"},
{certfile,"apiclient_cert.pem"}
],
HTTPOptions = [{ssl, SSLOptions}, {timeout, 5000}, {version, "HTTP/1.1"}],
%% +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Request = {ReqUrl, [], "application/x-www-form-urlencoded", iolist_to_binary(Str)},
httpc:request(post, Request, HTTPOptions, []).

使用xmerl解析xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
scan_str(Str) ->
{XmlElement, _Rest} = xmerl_scan:string(Str, [{space, normalize}]),
[XmlElement1] = xmerl_lib:remove_whitespace([XmlElement]),
XmlElement1.

value_of(Key, #xmlElement{} = X) ->
case xmerl_xs:select(Key, X) of
[#xmlElement{} = Find] ->
de_cdata(xmerl_xs:value_of(Find));
[] ->
[]
end.
de_cdata("![CDATA[" ++ Data) ->
[_,_|Data1] = lists:reverse(Data),
unescape_str(lists:reverse(Data1));
de_cdata(Data) ->
unescape_str(Data).

unescape_str(Str) ->
Str1 = unicode:characters_to_binary(Str),
GtEsc = re:replace(Str1, "&", "\\&", [global]),
LtEsc = re:replace(GtEsc, ">", ">", [global]),
AmpEsc = re:replace(LtEsc, "&lt;", "<", [global]),
Text = re:replace(AmpEsc, "&amp;", "\\&", [global]),
util:to_list(Text).

proplists转换为xml

1
2
3
4
5
6
7
export_xml(List) ->
Fields = lists:map(
fun({Key, Value}) ->
{Key, [], [util:to_list(Value)]}
end, List),
Xml = xmerl:export_simple([{xml, Fields}], xmerl_xml, [{prolog, ""}]),
Xml.

相对完整的逻辑代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
notice_wx(UserName, PlayerId, Amount, OrderNum) ->
%% 插入日志
insert_extract_log(OrderNum, Amount),

Url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers",

MchAppId = "wx1234567890",
MchId = 1234567890,
Key = "key1234567890",
Desc = "",
%% 生成随机字符串
RandStr = util:rand_str(16, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"),
DataT = [
{mch_appid, MchAppId},
{mchid, MchId},
{device_info, config:server_id()},
{nonce_str, RandStr},
{partner_trade_no, OrderNum},
{openid, UserName},
{check_name, "NO_CHECK"},
{amount, Amount},
{desc, Desc}
],
Data = lists:sort(DataT),
DataStrList = lists:map(
fun({K, V}) ->
io_lib:format("~p=~s", [K, util:to_list(V)])
end, Data),
DataStr1 = string:join(DataStrList, "&"),
DataStr = lists:concat([DataStr1, "&key=", Key]),
Sign = util:md5(DataStr),
Data1 = [{sign, util:to_upper(Sign)}|Data],
Str = export_xml(Data1),

%% POST请求
case request_post(Url, "", {data, Str}) of
{ok, {{_,200,"OK"}, _, Content}} ->
Xml = scan_str(Content),
Val = value_of("return_code", Xml),
case Val of
"SUCCESS" ->
Code = value_of("result_code", Xml),
case Code of
"SUCCESS" ->
WxPayNo = value_of("payment_no", Xml),
%% 更新日志
update_extract_log(OrderNum, WxPayNo, ?WX_REDBAT_EXTRACT_STATE_SUCC, "");
"FAIL" ->
ErrCode = value_of("err_code", Xml),
ErrCodeDesc = value_of("err_code_des", Xml),
%% 更新日志
update_extract_log(OrderNum, "", ErrCode, ErrCodeDesc)
end;
"FAIL" ->
Msg = value_of("return_msg", Xml),
update_extract_log(OrderNum, "", "FAIL", Msg),
?ERROR_MSG("return_msg: ~ts", [utf8_list_to_string(Msg)])
end;
Ret ->
?ERROR_MSG("ret:~p", [Ret])
end.

request_post(Url, Path, {data, Str}) ->
ReqUrl = lists:concat([Url, Path]),
SSLOptions = [
{keyfile,"apiclient_key.pem"},
{certfile,"apiclient_cert.pem"}
],
HTTPOptions = [{ssl, SSLOptions}, {timeout, 5000}, {version, "HTTP/1.1"}],
Request = {ReqUrl, [], "application/x-www-form-urlencoded", iolist_to_binary(Str)},
httpc:request(post, Request, HTTPOptions, []).

scan_str(Str) ->
{XmlElement, _Rest} = xmerl_scan:string(Str, [{space, normalize}]),
[XmlElement1] = xmerl_lib:remove_whitespace([XmlElement]),
XmlElement1.

value_of(Key, #xmlElement{} = X) ->
case xmerl_xs:select(Key, X) of
[#xmlElement{} = Find] ->
de_cdata(xmerl_xs:value_of(Find));
[] ->
[]
end.
de_cdata("![CDATA[" ++ Data) ->
[_,_|Data1] = lists:reverse(Data),
unescape_str(lists:reverse(Data1));
de_cdata(Data) ->
unescape_str(Data).

unescape_str(Str) ->
Str1 = unicode:characters_to_binary(Str),
GtEsc = re:replace(Str1, "&amp;", "\\&", [global]),
LtEsc = re:replace(GtEsc, "&gt;", ">", [global]),
AmpEsc = re:replace(LtEsc, "&lt;", "<", [global]),
Text = re:replace(AmpEsc, "&amp;", "\\&", [global]),
util:to_list(Text).

export_xml(List) ->
Fields = lists:map(
fun({Key, Value}) ->
{Key, [], [util:to_list(Value)]}
end, List),
Xml = xmerl:export_simple([{xml, Fields}], xmerl_xml, [{prolog, ""}]),
Xml.

utf8_list_to_string(List) ->
unicode:characters_to_list(list_to_binary(List)).

参考文档

  1. https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2