【问题标题】:Elixir httpc error on productionElixir httpc 生产错误
【发布时间】:2018-08-14 11:37:30
【问题描述】:

我想使用:httpc 作为我的 HTTP 客户端。

我使用 edeliver 进行发布管理等。我的.deliver/config.exs 中有:inets:httpc,例如:

  set applications: [
    :runtime_tools,
    :inets,
    :httpc
  ]

我还在mix.exs 中添加了:inets:extra_applications

这是我如何使用:httpc

headers =
  if apikey,
    do: [{'Content-Type', 'application/json'}, {'apikey', to_charlist(apikey)}],
    else: [{'Content-Type', 'application/json'}]

http_options = [timeout: @timeout, connect_timeout: @timeout]
options = []

request = {
  to_charlist(url),
  headers,
  'application/json',
  to_charlist(encoded_obj)
}

:post
|> :httpc.request(request, http_options, options)
|> handle_response()

我收到很多错误,例如:

=SUPERVISOR REPORT==== 6-Mar-2018::15:44:11 ===
     Supervisor: {local,httpc_handler_sup}
     Context:    child_terminated
     Reason:     {function_clause,
                     [{http_transport,close,
                          [undefined,#Port<0.21557>],
                          [{file,"http_transport.erl"},{line,346}]},
                      {gen_server,try_terminate,3,
                          [{file,"gen_server.erl"},{line,648}]},
                      {gen_server,terminate,10,
                          [{file,"gen_server.erl"},{line,833}]},
                      {proc_lib,init_p_do_apply,3,
                          [{file,"proc_lib.erl"},{line,247}]}]}
     Offender:   [{pid,<0.2596.1>},
                  {id,undefined},
                  {mfargs,{httpc_handler,start_link,undefined}},
                  {restart_type,temporary},
                  {shutdown,4000},
                  {child_type,worker}]

还有

15:44:11.743 [error] GenServer #PID<0.2595.1> terminating
** (FunctionClauseError) no function clause matching in :http_transport.close/2
    (inets) http_transport.erl:346: :http_transport.close(:undefined, #Port<0.21559>)
    (stdlib) gen_server.erl:648: :gen_server.try_terminate/3
    (stdlib) gen_server.erl:833: :gen_server.terminate/10
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:init_error, :error_sending, {#Reference<0.18155839.2531262466.203553>, {:error, :einval}}}

相同的错误报告不同。

这句话说了一些我也不太明白的东西:

15:44:11.741 [error] Bad value on output port 'tcp_inet'

我真的不明白为什么会这样。

我使用的是HTTPotion,但没有这个问题(虽然有其他问题)。

问题是这适用于我的开发机器。它也适用于我机器上的类似生产的虚拟机。但是当它在真正的生产服务器上运行时会抛出这个错误。

我很困惑!

【问题讨论】:

  • 错误是什么?
  • 对不起@Dogbert,我不小心点击了帖子:)
  • 在 erlang 中,当正文格式化为 json 时,我可以成功向 apache 服务器发出 httpc cgi post 请求,但是当正文被格式化时,我无法成功向 inets httpd 服务器发出 httpc cgi post 请求被格式化为 json。当正文格式化为x-www-form-urlencoded 时,我能够成功地向 inets httpd 服务器发出 httpc cgi post 请求。你会遇到类似的事情吗?
  • @7stud 这很奇怪。但是端点没有使用httpd,它是红隼。我想我需要比较 dev 和 prod erlang 版本。如果可以的话,我会用更多信息更新问题。

标签: erlang elixir httpc


【解决方案1】:

在erlang中,有httpc:request()函数的Request参数变量:

request(Method, Request, HTTPOptions, Options) -> 

Request参数变量的类型指定为:

Request = request()
request() = {url(), headers()}

其中url() = string()headers() = [header()],即一个列表,所以Request参数的形状需要是:

{string, []}

但是,你正在这样做:

request = {
  to_charlist(url),
  headers,
  'application/json',
  to_charlist(encoded_obj)
}

看起来它的形状是:

{string, [], string, string}

我不知道您为什么要在标题列表之外复制“application/json”的 Content-Type,而且我不清楚 to_charlist(encoded_obj) 应该是什么。我会尝试:

request = {
  to_charlist(url),
  headers
}

如果to_charlist(encoded_obj) 需要在 http 标头中,则将适当的键/值对添加到您的标头列表中。潜在的 http 标头 here。也许你需要:

headers = 
  if api,
     do: [{'Content-Type', 'application/json'}, 
          {'apikey', to_charlist(apikey)}, 
          {'Authorization, to_charlist(encoded_obj)} ],
     else: [{'Content-Type', 'application/json'}, 
            {'Authorization, to_charlist(encoded_obj)} ]

最好写成这样:

base_headers = [
    {'Content-Type', 'application/json'},
    {'Authorization', to_charlist(encoded_obj)}
]

request_headers = 
    if apikey,
        do: [ {'apikey', to_charlist(apikey)} | base_headers ],
        else: base_headers

问题是这适用于我的开发机器。它也适用于 我的机器上也有类似生产的虚拟机。但它会抛出这个错误 当它在真正的生产服务器上运行时。

那么,请看这里:

Bad value on output port 'tcp_inet'

【讨论】:

  • 仔细阅读文档。该 4 元素元组是 url、标题、内容类型和正文。另外,to_charlist 用于将 Elixir 字符串转换为 Erlang 字符串。
  • @vfsoraki,哪个文件?
  • @vfsoraki,啊,我明白了。我错过了管道:| {url(), headers(), content_type(), body()}
猜你喜欢
  • 2021-02-14
  • 2013-12-05
  • 1970-01-01
  • 1970-01-01
  • 2013-07-30
  • 2016-08-10
  • 2018-11-01
  • 2017-04-11
  • 1970-01-01
相关资源
最近更新 更多