【问题标题】:parsing json return from http in erlang在erlang中解析从http返回的json
【发布时间】:2012-12-07 03:21:49
【问题描述】:

我用这段代码测试:

get_fee(Transaction,SourceNumber,Amount, Currency) ->
Url = lists:concat(["http://localhost/test.php","?transaction=", Transaction, "&saccount=", SourceNumber,Amount,"&currency=",Currency]),
        inets:start(),
        {Flag, Response} = http:request(get, {Url, []}, [], []),
        case Flag of
            ok ->
                { { _, ReturnCode, _ }, _, Body } = Response,

                if ReturnCode =:= 200 ->
                        {ok,{_,[{_,Code},{_,Permission},{_,Payer},{_,Payee}]}} = json:decode_string(Body),
                            case Permission of true ->
                                if Code =:= 200 ->
                                    {ok,{Code, Payer, Payee}};
                                Code =:= 204 ->
                                    {nok,{Code, not_found}};
                                true ->
                                    {nok,{Code, parameter_error}}
                                end;
                            false ->
                                {nok,{Code, parameter_error}}
                            end;
                    true->
                        {error, http_error}
                end;
            error ->
                case Response of
                    nxdomain -> {error, dns_error};
                    _ -> {error, network_error}

                end
        end.

http 的响应是:{"code":200,"permission":true,"fee_payer":0,"fee_payee":19}

但现在我喜欢做同样的想法,但在这种情况下 http 的返回例如是:

{"CIN":"08321224","Name":21}

所以在这种情况下我只有 CIN 和名称

我尝试改变以前的

get_fee(Num) ->
    Url = lists:concat(["http://localhost/GTW/Operation.php","?ACCOUNT_NUM=", Num]),




            inets:start(),
             {Flag, Response} = http:request(get, {Url, []}, [], []),
            case Flag of
                ok ->
                    { { _, ReturnCode, _ }, _, Body } = Response,
                    %% for debug
                   io:format("~p~n",[ReturnCode]),
                    if ReturnCode =:= "08321224" ->
                            {ok,{_,[{_,CIN},{_,Name}]}} = json:decode_string(Body),
                                case Name of 21 ->
                                                 io:format(CIN),
                                                 io:format(Name),
                                    if CIN =:= "08321224"->
                                        {ok,{CIN, Name}};
                                    CIN =:= 204 ->
                                        {nok,{CIN, not_found}};
                                    true ->
                                        {nok,{CIN, parameter_error}}
                                    end;
                                false ->
                                    {nok,{CIN, parameter_error}}
                                end;
                        true->
                            {error, http_error}
                    end;
                error ->
                    case Response of
                        nxdomain -> {error, dns_error};
                        _ -> {error, network_error}
                    %% for debug
                    %%io:format("pass2~n ~p~n",[Response]),
                    end
  end.

但它显示:

test:get_fee("0001").
200
{error,http_error}

【问题讨论】:

  • 问题是什么?这是问答网站,而不是“我们帮助您查找错误”网站。
  • 另外,该代码可能确实需要一些惯用的 Erlang。如果您以正确的措辞重新提出问题,我会尽力提供帮助,除非有人比我更胜一筹。
  • 当我从http返回四个json格式的值时,第一个erlang函数起作用 {"code": 200, "permission": true, "fee_payer": 0, "fee_payee": 19}请求
  • 现在我有一个 http 请求,它只返回 json 格式的两个值 {"CIN": "08321224", "Name": 21} 所以我想开发一个适用于这种类型的 erlang 函数返回值(只有两个http请求值)我想启发前一个函数(从第一个函数使用四个从http请求返回的值)我的问题是:我们如何更改erlang函数get_fee的代码为了处理我的新 http 请求(使用我的新概念)
  • 你在使用 Erlang JSON Parser 库吗?如果是这样,您使用的是哪一个?我建议在您的问题中,您只需向我们展示 JSON 示例数据,然后我们将向您展示如何解析它。只需将 JSON 显示出来,然后我们将获取一个库并解析该数据,因此您可以在您的代码中执行相同的操作。

标签: json erlang


【解决方案1】:

所以我会在这里挑剔风格,因为如果你遵循 Erlang 的语义思想会更好:

get_fee(Num) ->
    Url = lists:concat(["http://localhost/GTW/Operation.php","?ACCOUNT_NUM=", Num]),
    inets:start(),

这是错误的起点inets。它应该在这个函数之外启动,因为你只需要 做这个。

{Flag, Response} = http:request(get, {Url, []}, [], []),

这部分最好用模式匹配编码。 FlagResponse的区分可以 直接用简单的匹配解码。写,

case http:request(get, {Url, []}, [], []) of
  {ok, {{_, 200, _}, _, Body}} ->
      {ok, R} = json:decode_string(Body),
      get_fee_decode_(get_cin(R), get_name(R));
  {error, Reason} -> {error, Reason}
end.

我建议不要将{error, nxdomain} 更改为{error, dns_error},因为nxdomain 完美 在任何情况下都对这种情况进行编码。只需将错误元组传递给调用者并让他处理即可。

get_fee_decode_("08321224" = CIN, 21 = Name) -> {ok, {CIN, Name}};
get_fee_decode_("204" = CIN, 21) -> {nok, {CIN, not_found}};
get_fee_decode_(CIN, _Name) -> {nok, {CIN, parameter_error}};

引入一个像这样的新函数来处理代码库的内部部分。并将匹配提升到 顶层。从长远来看,这有助于将您的代码解耦为函数。

请注意,在 JSON 结构中,“对象”没有顺序,因此您不能假设该结构是

{"code":200,"permission":true,"fee_payer":0,"fee_payee":19}

但根据 JSON,解码不必保留此结构。所以一个有效的解码可能是:

[{"fee_payee", 19}, {"fee_payer", 0}, {"permission", true}, {"code", 200}]

这将无法在您的代码中匹配,并且您稍后会为自己设置一些令人讨厌的错误。

你想要一些类似的东西:

get_fee_payer(PL) -> proplists:get_value("fee_payer", PL).

您的编程风格会出现问题的另一件事是您隐藏了错误信息案例。在 Erlang 中,您通常可以避免只处理代码中的“快乐路径”,而无需处理所有错误,直到您知道代码库中存在什么样的错误。然后您可以开始慢慢添加错误处理。如果可以避免,防御性编程不是你应该做的事情。

【讨论】:

    【解决方案2】:

    你变了:

    if ReturnCode =:= 200 ->
    

    到:

    if ReturnCode =:= "08321224" ->
    

    但是,这需要在您的版本中保持不变。 200 是“OK”的 HTTP 状态码——这里的第一步是验证服务器是否确实处理了请求并返回了肯定的回复。您只能在 Body 中找到该号码 - 这就是 if CIN =:= "08321224"-> 部分的用途。

    【讨论】:

      猜你喜欢
      • 2010-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多