我正在使用httpc:request
将一些数据发布到远程服务。我有帖子工作,但帖子的 body() 中的数据按原样通过,没有任何 URL 编码,这会导致帖子在被远程服务解析时失败。
Erlang 中是否有类似于CGI.escape
Ruby 中用于此目的的函数?
我正在使用httpc:request
将一些数据发布到远程服务。我有帖子工作,但帖子的 body() 中的数据按原样通过,没有任何 URL 编码,这会导致帖子在被远程服务解析时失败。
Erlang 中是否有类似于CGI.escape
Ruby 中用于此目的的函数?
我也遇到了 HTTP 模块中缺少此功能的情况。
事实证明,这个功能实际上在 erlang 发行版中是可用的,你只需要仔细研究一下。
> edoc_lib:escape_uri("luca+more@here.com").
"luca%2bmore%40here.com"
这与 Ruby 中的 CGI.escape 类似,但 URI.escape 的行为略有不同:
> CGI.escape("luca+more@here.com")
=> "luca%2Bmore%40here.com"
> URI.escape("luca+more@here.com")
=> "luca+more@here.com"
至少在 R15 中有http_uri:encode/1可以完成这项工作。我也不建议使用 edoc_lib:escape_uri 将 '=' 转换为 %3d 而不是 %3D,这给我带来了一些麻烦。
你可以在这里找到YAWS url_encode 和 url_decode 例程
它们相当简单,尽管注释表明所有标点字符的编码并不是 100% 完成的。
这是一个完成这项工作的简单函数。它旨在直接与 inets httpc 一起使用。
%% @doc A function to URL encode form data.
%% @spec url_encode(formdata()).
-spec(url_encode(formdata()) -> string()).
url_encode(Data) ->
url_encode(Data,"").
url_encode([],Acc) ->
Acc;
url_encode([{Key,Value}|R],"") ->
url_encode(R, edoc_lib:escape_uri(Key) ++ "=" ++ edoc_lib:escape_uri(Value));
url_encode([{Key,Value}|R],Acc) ->
url_encode(R, Acc ++ "&" ++ edoc_lib:escape_uri(Key) ++ "=" ++ edoc_lib:escape_uri(Value)).
示例用法:
httpc:request(post, {"http://localhost:3000/foo", [],
"application/x-www-form-urlencoded",
url_encode([{"username", "bob"}, {"password", "123456"}])}
,[],[]).
如果有人需要在 erlang 中使用 utf-8 编码 uri:
https://gist.github.com/3796470
前任。
Eshell V5.9.1 (abort with ^G)
1> c(encode_uri_rfc3986).
{ok,encode_uri_rfc3986}
2> encode_uri_rfc3986:encode("テスト").
"%e3%83%86%e3%82%b9%e3%83%88"
3> edoc_lib:escape_uri("テスト").
"%c3%86%c2%b9%c3%88" # output wrong: ƹÈ
回答我自己的问题...我在 ibrowse 中找到了这个库!
http://www.erlware.org/lib/5.6.3/ibrowse-1.4/ibrowse_lib.html#url_encode-1
url_encode/1
url_encode(Str) -> UrlEncodedStr
Str = string()
UrlEncodedStr = string()
URL 编码基于 RFC 1738 的字符串。返回一个平面列表。
我想我可以使用它来进行编码并仍然使用 http:
这是函数的“分支”,edoc_lib:escape_uri
它改进了对 UTF-8 的支持并且还支持二进制文件。
escape_uri(S) when is_list(S) ->
escape_uri(unicode:characters_to_binary(S));
escape_uri(<<C:8, Cs/binary>>) when C >= $a, C =< $z ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C >= $A, C =< $Z ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C >= $0, C =< $9 ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C == $. ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C == $- ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) when C == $_ ->
[C] ++ escape_uri(Cs);
escape_uri(<<C:8, Cs/binary>>) ->
escape_byte(C) ++ escape_uri(Cs);
escape_uri(<<>>) ->
"".
escape_byte(C) ->
"%" ++ hex_octet(C).
hex_octet(N) when N =< 9 ->
[$0 + N];
hex_octet(N) when N > 15 ->
hex_octet(N bsr 4) ++ hex_octet(N band 15);
hex_octet(N) ->
[N - 10 + $a].
请注意,由于使用了 unicode:characters_to_binary,它仅适用于 R13 或更新版本。
示例用法是:
9> httpc:request("http://httpbin.org/get?q=" ++ mylib_app:escape_uri("☺")).
{ok,{{"HTTP/1.1",200,"OK"},
[{"connection","keep-alive"},
{"date","Sat, 09 Nov 2019 21:51:54 GMT"},
{"server","nginx"},
{"content-length","178"},
{"content-type","application/json"},
{"access-control-allow-credentials","true"},
{"access-control-allow-origin","*"},
{"referrer-policy","no-referrer-when-downgrade"},
{"x-content-type-options","nosniff"},
{"x-frame-options","DENY"},
{"x-xss-protection","1; mode=block"}],
"{\n \"args\": {\n \"q\": \"\\u263a\"\n }, \n \"headers\": {\n \"Host\": \"httpbin.org\"\n }, \n \"origin\": \"11.111.111.111, 11.111.111.111\", \n \"url\": \"https://httpbin.org/get?q=\\u263a\"\n}\n"}}
我们发送一个带有转义查询参数的请求,并看到我们得到了正确的 Unicode 代码点。
AFAIK 标准库中没有 URL 编码器。认为我从 YAWS 或其他 Erlang Web 服务器之一“借用”了以下代码:
% Utility function to convert a 'form' of name-value pairs into a URL encoded
% content string.
urlencode(Form) ->
RevPairs = lists:foldl(fun({K,V},Acc) -> [[quote_plus(K),$=,quote_plus(V)] | Acc] end, [],Form),
lists:flatten(revjoin(RevPairs,$&,[])).
quote_plus(Atom) when is_atom(Atom) ->
quote_plus(atom_to_list(Atom));
quote_plus(Int) when is_integer(Int) ->
quote_plus(integer_to_list(Int));
quote_plus(String) ->
quote_plus(String, []).
quote_plus([], Acc) ->
lists:reverse(Acc);
quote_plus([C | Rest], Acc) when ?QS_SAFE(C) ->
quote_plus(Rest, [C | Acc]);
quote_plus([$\s | Rest], Acc) ->
quote_plus(Rest, [$+ | Acc]);
quote_plus([C | Rest], Acc) ->
<<Hi:4, Lo:4>> = <<C>>,
quote_plus(Rest, [hexdigit(Lo), hexdigit(Hi), ?PERCENT | Acc]).
revjoin([], _Separator, Acc) ->
Acc;
revjoin([S | Rest],Separator,[]) ->
revjoin(Rest,Separator,[S]);
revjoin([S | Rest],Separator,Acc) ->
revjoin(Rest,Separator,[S,Separator | Acc]).
hexdigit(C) when C < 10 -> $0 + C;
hexdigit(C) when C < 16 -> $A + (C - 10).