Как вы URL-кодируете параметры в Erlang?

Я использую httpc:request для отправки некоторых данных в удаленную службу. У меня сообщение работает, но данные в теле () сообщения поступают как есть, без какой-либо кодировки URL, которая приводит к сбою сообщения при анализе удаленной службой.

Есть ли в Erlang функция, похожая на CGI.escape в Ruby для этой цели?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
20
0
13 882
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

AFAIK в стандартных библиотеках нет кодировщика URL. Думаю, я «позаимствовал» следующий код у YAWS или, возможно, одного из других веб-серверов Erlang:

% 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).

Чтобы ответить на свой вопрос ... Я нашел эту библиотеку в 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:

Ответ принят как подходящий

Вы можете найти здесь YAWS процедуры url_encode и url_decode

Они довольно просты, хотя комментарии указывают на то, что кодирование не для всех знаков препинания завершено на 100%.

Ссылка вроде битая - может, это поможет? yaws.hyber.org/yman.yaws?page=yaws_api

skwidbreth 01.06.2018 19:13

Я также столкнулся с отсутствием этой функции в модулях HTTP.

Оказывается, эта функциональность действительно доступна в дистрибутиве erlang, вам просто нужно присмотреться.

> edoc_lib:escape_uri("[email protected]").
"luca%2bmore%40here.com"

Это ведет себя как CGI.escape в Ruby, есть также URI.escape, который ведет себя немного иначе:

> CGI.escape("[email protected]")
 => "luca%2Bmore%40here.com" 
> URI.escape("[email protected]")
 => "[email protected]" 

edoc_lib

Похоже, этот совет устарел - перейдите по ссылке, и вы увидите, что edoc_lib:escape_uri - это MIA. Не уверен, в какой версии erlang было внесено это изменение.

jtmoulia 01.04.2015 02:34
Он там и экспортируется. I'm not sure why it's not in the man page.
mqsoh 30.05.2015 05:59

У меня сработало, вроде нормально.

skwidbreth 01.06.2018 19:19

Вот простая функция, которая выполняет свою работу. Он предназначен для работы напрямую с 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"}])}
             ,[],[]).

Вот «вилка» функции 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.

По крайней мере, в R15 есть http_uri: кодировать / 1, который выполняет эту работу. Я бы также не рекомендовал использовать edoc_lib: escape_uri для перевода знака '=' в% 3d вместо% 3D, что вызвало у меня некоторые проблемы.

http_uri:encode хорошо работает с символами ASCII, но ничего не делает с символами больше 127 (конечно, трудно сказать, что он должен делать, учитывая, что функция не знает желаемой выходной кодировки).

legoscia 30.12.2014 15:27

«... но ничего не делает с символами больше 127». или управляющие символы. :(

juan.facorro 24.10.2017 18:39

Если кому-то нужно закодировать uri, который работает с utf-8 в erlang:

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: ƹÈ

Другие вопросы по теме