yaws appmods Accept-Language A 记录不正确

Posted

技术标签:

【中文标题】yaws appmods Accept-Language A 记录不正确【英文标题】:yaws appmods Accept-Language A record is not correct 【发布时间】:2020-02-02 08:11:34 【问题描述】:

多年来,我一直使用 docker 容器中的 yaws,基本上取自 https://github.com/segeda/docker-yaws/blob/master/Dockerfile:

FROM erlang:20-alpine
...
&& git clone https://github.com/klacke/yaws.git /yaws-src \
...

以前运行良好,但突然我的代码失败了,我找不到错误。我什至找不到以前工作的 git 版本,所以我怀疑它可能不是代码错误,但是——它可能是什么?

它不可能是我的代码,对吗?因为我将其归结为http://yaws.hyber.org/appmods.yaws 中给出的示例并产生了相同的错误:

%% this is my appmod called from yaws

-module(myurl).
-author('kklepper').
-include("../../include/yaws_api.hrl").
%-include("/usr/local/lib/yaws/include/yaws_api.hrl"). 
% relative or absolute -- either way same result
-export([out/1]).

-define(debug, true).
-ifdef(debug).
-define(trace(Str, X), io:format("Mod:~w line:~w ~p ~p~n", 
                                 [?MODULE,?LINE, Str, X])).
-else.
-define(trace(X, Y), true).
-endif.

box(Str) ->
    'div',[class,"box"],
     pre,[],Str.

out(A) ->
?trace('A', A),
    ehtml,
     [p,[],
       box(io_lib:format("A#arg.appmoddata = ~p~n"
                         "A#arg.appmod_prepath = ~p~n"
                         "A#arg.querydata = ~p~n",
                         [A#arg.appmoddata,
                          A#arg.appmod_prepath,
                          A#arg.querydata]))].

文件yaws_api.hrl 曾经并且现在仍然存在:

/yaws # ls -la /usr/local/lib/yaws/include/yaws_api.hrl
-rw-r--r--    1 1000     50            5563 May 13  2018 /usr/local/lib/yaws/include/yaws_api.hrl

使用trace,您可以看到A 记录不正确——没有A#arg.querydata 等——因此出现错误。为什么?

显然,querydata,例如:lg=en

Mod:myurl line:22 'A' arg,#Port<0.2934>,
                          10,255,0,2,52801,
                          headers,"keep-alive",
                              "text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, image/apng, */*;q=0.8, application/signed-exchange;v=b3",
                              "voxx.b2d",undefined,undefined,undefined,
                              undefined,undefined,undefined,undefined,
                              "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36",
                              undefined,[],undefined,undefined,undefined,
                              undefined,undefined,undefined,undefined,
                              undefined,
                              [http_header,11,'Accept-Language',undefined,
                                   "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
                               http_header,10,'Accept-Encoding',undefined,
                                   "gzip, deflate",
                               http_header,0,"Upgrade-Insecure-Requests",
                                   undefined,"1"],
                          http_request,'GET',
                              abs_path,"/industries?lg=en",
                              1,1,
                          http_request,'GET',
                              abs_path,"/industries?lg=en",
                              1,1,
                          undefined,"/industries","lg=en","industries","/ci",
                          "/","/ci/industries",undefined,undefined,<0.163.0>,
                          [],[],[],"/industries",myurl

=ERROR REPORT==== 4-Oct-2019::00:46:06 ===


ERROR erlang code threw an uncaught exception:
 File: appmod:0
Class: error
Exception: badrecord,arg
Req: http_request,'GET',abs_path,"/industries?lg=en",1,1
Stack: [myurl,out,1,
               [file,"/usr/local/lib/yaws/voxx/ebin/myurl.erl",line,29],
        yaws_server,deliver_dyn_part,8,
                     [file,"yaws_server.erl",line,2921],
        yaws_server,aloop,4,[file,"yaws_server.erl",line,1274],
        yaws_server,acceptor0,2,[file,"yaws_server.erl",line,1073],
        proc_lib,init_p_do_apply,3,[file,"proc_lib.erl",line,247]]

到现在为止,我的想法已经用完了。有什么提示吗?

有问题的数据似乎在那里。我对语言数据很感兴趣,并且习惯于从A 获得接受的语言,如下所示:

get_lang(A) -> 
    find_lang(find_http_header('Accept-Language', (A#arg.headers)#headers.other)).

find_http_header(Key,Headers) when is_list(Headers) ->
        case lists:keysearch(Key,3,Headers) of
            value,_,_,_,_,Value -> Value;
            false -> undefined
        end.

find_lang(AcceptLanguage) ->
    case AcceptLanguage of
        undefined ->
            "en";
        _ ->
            L = lists:nth(1,string:tokens(
                lists:nth(1,string:tokens(
                    lists:nth(1,string:tokens(AcceptLanguage, ";"))
                    ,","))
            ,"-")),
            L
    end.

没有正确的数据结构,这是行不通的。

【问题讨论】:

Yaws 的当前版本 2.0.7 和 Yaws master 都通过了对 Erlang/OTP 版本从 17.0 到 22.1 的所有测试,并且测试包括对 querydata 的访问987654336@记录。我怀疑您的 appmod 尚未使用 #arg 记录的当前定义重新编译。 @SteveVinoski 好吧,我的版本是 2.0.7,并且我进行了交互测试,因此会自动重新编译。 我复制了您在问题中发布的myrul.erl 代码,对其进行了编译,在我的yaws.conf 中将其指定为appmod,通过Yaws 2.0.7 向它发送了一个请求,并且运行良好。我建议检查您的加载路径以确保您获得正确的myurl appmod,并且我还要确保您只安装了一次 Yaws,以排除任何意外混合新旧版本的情况。如果在那之后您仍然遇到问题,也许可以尝试直接与我联系,以便我们找到进一步调试的方法。 【参考方案1】:

您在问题中包含的详细信息表明,您的 appmod 在尝试访问 Yaws 传递给它的 #arg 记录时遇到了 badrecord 异常。有几种方法可以获得这样的异常:

    将预期记录类型以外的数据类型的实例传递给函数。在这种情况下不会发生这种情况,因为 Yaws 正在调用该函数并且正确地传递了一个 #arg 记录实例。 用同一记录的两个不同定义编译调用者和被调用函数。我们可以在 Erlang shell 中模拟这个问题,如下所示: 首先,定义一条记录#arg,包含两个字段 定义一个函数,将该记录的一个实例作为参数并返回其中一个字段的值 将 shell 中的记录重新定义为只有一个字段 将重新定义的记录的实例传递给函数,这将导致badrecord 异常
        1> rd(arg, f,g).
        arg
        2> F = fun(A) -> A#arg.f end.
        #Fun<erl_eval.7.126501267>
        3> rd(arg, f).
        arg
        4> F(#argf=1).
        ** exception error: badrecord,arg

由于您使用的是 Yaws 2.0.7 并且您还从 github 克隆 Yaws,因此您很可能正在针对 Yaws 主分支编译您的代码的某些部分,可能是您的 appmod,然后针对 2.0 运行它。 7.在我在 github 上标记 Yaws 2.0.7 之后的某个时间,我接受了 change that added a new field 到 #arg 记录定义。这意味着 Yaws 2.0.7 创建并传递给您的 appmod 的任何 #arg 记录都会导致 badrecord 异常,因为 appmod 需要包含附加字段的记录。

我可以想出几个方法来避免这个问题:

摆脱您的 Yaws github 克隆并针对您安装的 Yaws 2.0.7 构建所有内容。 在您的 Yaws 克隆中,git checkout yaws-2.0.7 以便您从克隆中访问或使用的任何内容都与您的 Yaws 2.0.7 安装中的相同。 卸载 Yaws 2.0.7,然后从 Yaws 克隆编译和安装。也许先应用一个本地标签,然后从它构建和安装,这样您的部署可以更容易地复制,这样您就可以从 github 获取 Yaws 更新而不会破坏本地任何东西。

【讨论】:

以上是关于yaws appmods Accept-Language A 记录不正确的主要内容,如果未能解决你的问题,请参考以下文章

Erlang的Web库和框架

Erlang的Web库和框架

如何让 myBinder.org 直接启动到 Appmode

Yaws 文件未正确渲染

pitch, yaw, roll

Yaws 进程死亡:badmatch,<<>>