使用 laminas-http 代理适配器发出的 HTTP 请求失败

问题描述

设置

一个 Omeka S (v3.0.1) 实例在 Red Hat OpenShift 容器中运行,并配置为使用 laminas-http 代理适配器通过代理服务器发出 http 请求。

/omeka-s/config/local.config.PHP
'http_client' => [
        'adapter'    => \Laminas\Http\Client\Adapter\Proxy::class,'proxy_host' => ‘<proxy.address>’,'proxy_port' => <port number>,],

问题

尝试使用 oembed 媒体创建项目并使用 CSVImport 模块时出现问题。

代理适配器在尝试建立 SSL 连接时抛出异常,报告应用程序无法连接到目标服务器。 PHP 警告提供了更多细节,指出代理身份验证是问题所在。

容器内的其他程序通过相同的代理发出 http 请求,按预期工作。示例包括 yum、curl 和用于从 omeka S 发送电子邮件的 smtp 程序。

根据我在下面的尝试,问题似乎与 laminas、代理和/或目标服务器之间的交互有关。

Laminas\Http\Client\Adapter\Exception\RuntimeException: Unable to connect to HTTPS server through proxy: Could not negotiate secure connection. in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP:296
Stack trace:
#0 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP(165): Laminas\Http\Client\Adapter\Proxy->connectHandshake('vimeo.com',443,'1.1',Array)
#1 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client.PHP(1457): Laminas\Http\Client\Adapter\Proxy->write('GET',Object(Laminas\Uri\Http),Array,'')
#2 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client.PHP(945): Laminas\Http\Client->doRequest(Object(Laminas\Uri\Http),'GET',true,'')
#3 /opt/app-root/src/omeka-s/application/src/Media/Ingester/OEmbed.PHP(142): Laminas\Http\Client->send()
#4 /opt/app-root/src/omeka-s/application/src/Media/Ingester/OEmbed.PHP(73): omeka\Media\Ingester\OEmbed->makeRequest('https://vimeo.c...','OEmbed URL',Object(omeka\Stdlib\ErrorStore))
#5 /opt/app-root/src/omeka-s/application/src/Api/Adapter/MediaAdapter.PHP(159): omeka\Media\Ingester\OEmbed->ingest(Object(omeka\Entity\Media),Object(omeka\Api\Request),Object(omeka\Stdlib\ErrorStore))
...
2021-03-02T20:05:21+00:00 ERR (3): Laminas\Http\Client\Adapter\Exception\RuntimeException: Unable to connect to HTTPS server through proxy: Could not negotiate secure connection. in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP:296
Stack trace:
#0 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP(165): Laminas\Http\Client\Adapter\Proxy->connectHandshake('www.dropBox.com','')
#3 /opt/app-root/src/omeka-s/application/src/File/Downloader.PHP(64): Laminas\Http\Client->send()
#4 /opt/app-root/src/omeka-s/application/src/Media/Ingester/Url.PHP(63): omeka\File\Downloader->download(Object(Laminas\Uri\Http),Object(omeka\Stdlib\ErrorStore))
#5 /opt/app-root/src/omeka-s/application/src/Api/Adapter/MediaAdapter.PHP(159): omeka\Media\Ingester\Url->ingest(Object(omeka\Entity\Media),Object(omeka\Stdlib\ErrorStore))
...
Warning: stream_socket_enable_crypto(): Peer certificate CN=`vimeo.map.fastly.net' did not match expected CN=`<proxy.address>’ in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP on line 289
Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP on line 289
...

尝试了什么

禁用 SSL 对等验证。

/omeka-s/config/local.config.PHP
'http_client' => [
    ...
    'sslverifypeer' => false,'sslverifypeername' => false,

结果是多次尝试后可以导入项目,但现在请求可能会由于两个新原因失败:连接可能会失败并出现与上述相同的异常,但 PHP 报告这是由于握手超时,以及代理或目标服务器可能会返回格式错误/空的响应。

Warning: stream_socket_enable_crypto(): SSL: Handshake timed out in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP on line 289
Laminas\Http\Exception\invalidargumentexception: A valid response status line was not found in the provided string in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Response.PHP:266
Stack trace:
#0 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Response.PHP(204): Laminas\Http\Response->parseStatusLine('')
#1 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP(271): Laminas\Http\Response::fromString('')
#2 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.PHP(165): Laminas\Http\Client\Adapter\Proxy->connectHandshake('vimeo.com',Array)
#3 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client.PHP(1457): Laminas\Http\Client\Adapter\Proxy->write('GET','')
#4 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client.PHP(945): Laminas\Http\Client->doRequest(Object(Laminas\Uri\Http),'')
#5 /opt/app-root/src/omeka-s/application/src/Media/Ingester/OEmbed.PHP(142): Laminas\Http\Client->send()
#6 /opt/app-root/src/omeka-s/application/src/Media/Ingester/OEmbed.PHP(73): omeka\Media\Ingester\OEmbed->makeRequest('https://vimeo.c...',Object(omeka\Stdlib\ErrorStore))
#7 /opt/app-root/src/omeka-s/application/src/Api/Adapter/MediaAdapter.PHP(159): omeka\Media\Ingester\OEmbed->ingest(Object(omeka\Entity\Media),Object(omeka\Stdlib\ErrorStore))
...

切换到 laminas-http curl 适配器。

首先测试curl命令行工具和一个使用PHP curl库的测试PHP程序,确认可以成功使用代理。没有一个测试请求失败。不过,响应时间变化很大。有些请求需要 40 多秒才能完成。

切换到 curl 适配器让 omeka S 能够成功下载 oembed 资源。我在使用该应用程序时看到请求时间的相同变化,并且它多次报告 504 网关超时错误。当我导航回管理面板时,返回 504 错误响应的项目​​仍然显示为已成功创建。

我不确定 504 是来自容器的 apache 实例、代理还是目标网站。

'http_client' => [
        'adapter'    => \Laminas\Http\Client\Adapter\Curl::class,'proxy_port' => <proxy port>,

通过代理路由非容器化实例。

待定。如果可以复制错误,则问题出在 laminas 和代理之间。如果不能,则问题是在容器上下文中使用了 laminas。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)