yaws appmods Accept-Language A 记录不正确
yaws appmods Accept-Language A record is not correct
我使用 docker 容器中的雅司病工作多年,基本上取自 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.
没有正确的数据结构,这是行不通的。
您在问题中包含的详细信息表明,您的 appmod 在尝试访问 Yaws 传递给它的 #arg
记录时出现 badrecord
异常。有几种方法可以获得这样的异常:
- 将预期记录类型以外的数据类型的实例传递给函数。在这种情况下不会发生这种情况,因为 Yaws 正在调用该函数并正确传递
#arg
记录实例。
- 用同一记录的两个不同定义编译调用者和被调用函数。我们可以在 Erlang shell 中模拟这个问题,如下所示:
- 首先,定义一个包含两个字段的记录
#arg
- 定义一个函数,该函数将该记录的实例作为参数,returns其中一个字段的值
- 重新定义 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(#arg{f=1}).
** exception error: {badrecord,arg}
由于您使用的是 Yaws 2.0.7 并且您还从 github 克隆了 Yaws,因此您可能正在针对 Yaws master 分支编译部分代码,可能是您的 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 更新而不会破坏任何本地内容。
我使用 docker 容器中的雅司病工作多年,基本上取自 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.
没有正确的数据结构,这是行不通的。
您在问题中包含的详细信息表明,您的 appmod 在尝试访问 Yaws 传递给它的 #arg
记录时出现 badrecord
异常。有几种方法可以获得这样的异常:
- 将预期记录类型以外的数据类型的实例传递给函数。在这种情况下不会发生这种情况,因为 Yaws 正在调用该函数并正确传递
#arg
记录实例。 - 用同一记录的两个不同定义编译调用者和被调用函数。我们可以在 Erlang shell 中模拟这个问题,如下所示:
- 首先,定义一个包含两个字段的记录
#arg
- 定义一个函数,该函数将该记录的实例作为参数,returns其中一个字段的值
- 重新定义 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(#arg{f=1}).
** exception error: {badrecord,arg}
由于您使用的是 Yaws 2.0.7 并且您还从 github 克隆了 Yaws,因此您可能正在针对 Yaws master 分支编译部分代码,可能是您的 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 更新而不会破坏任何本地内容。