AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 837104
Accepted
Brian Beckett
Brian Beckett
Asked: 2017-03-09 12:15:17 +0800 CST2017-03-09 12:15:17 +0800 CST 2017-03-09 12:15:17 +0800 CST

Apache 2.4.7 mod_proxy_wstunnel 隧道太多(HTTP 和 WS)

  • 772

我在 Ubuntu 14.04 LTS 上运行 Apache 2.4.7 作为反向代理。此 Apache 服务器充当许多不同后端应用程序的入口点,这些应用程序通过<Location>块中的不同 mod_proxy 配置访问

我需要为使用 WebSockets 的应用程序提供反向代理访问。该应用程序是一个 Java Spring 应用程序,它通过 HTTP 提供 HTML 和其他静态文件,然后在页面加载后使用 WebSocket 获取动态数据。

我Nginx使用以下配置让应用程序在后面运行:

location /newapp/ {
    proxy_pass http://newapp.example.com:8080/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

不幸的是,由于需要 Nginx 上不可用的 Apache 身份验证模块,我无法在生产中使用它。

在伪 Apache-config 中,我想做的是:

<Location /newapp/>
    if not WebSockets:
        ProxyPass http://newapp.example.com:8080/
        ProxyPassReverse /
    else
        ProxyPass ws://newapp.example.com:8080/
        ProxyPassReverse /
</Location>

Apachemod_proxy_wstunnel模块让我认为这应该是可能的。WebSocket 是在 URL 上访问的/api/socket/...,所以我尝试ProxyPass使用单独的<Location>块分隔两种类型:

<Location /newapp/>
    ProxyPass http://newapp.example.com:8080/ disablereuse=on
    ProxyPassReverse /

    ProxyPassReverseCookieDomain newapp.example.com apps.example.com
    ProxyPassReverseCookiePath http://newapp.example.com:8080/ /newapp/
</Location>

<Location /newapp/api/socket/>
    ProxyPass ws://newapp.example.com:8080/api/socket/
    ProxyPassReverse /
</Location>

这最初是有效的——浏览器请求http://apps.example.com/newapp/,页面通过 HTTP 加载,静态资产被加载,JavaScript 代码连接到 websocket,一切都很棒。

但是,当通过 HTTP 发出新请求时,例如 for GET /newapp/static/someimage.png,就会出现问题。此请求与 WebSocket 位置不匹配,因此我希望它能够代理GET /static/someimage.png到http://newapp.example.com:8080/.

相反,应用程序服务器收到请求GET /newapp/static/someimage.png并返回 404,因为这不是它知道的 URL。这会破坏应用程序,因为应该工作的 HTTP 请求会失败。

笔记:

  • 这不仅发生在图像上 -GET /newapp/api/ajax/someapicall也被错误地代理。
  • 这并不总是发生。在测试完成这个问题的过程中,我设法让应用程序完全运行。这可能是基于时间的——在发出任何新的 HTTP 请求之前,我让应用程序运行了几分钟而没有与之交互。当我确实发出新的 HTTP 请求时,它们正确地通过了。
  • 禁用该<Location /newapp/api/socket/>部分会导致两件事发生 - WebSocket 无法连接,并且 HTTP 请求继续工作。
  • 通过浏览器的刷新按钮刷新页面后,我发现了这个问题。我没有再次加载页面,而是看到了应用程序的 404 屏幕。

我认为正在发生的事情:

我认为mod_proxy_wstunnel,一旦被第一个匹配请求激活/newapp/api/socket/,就会接管来自客户端的所有进一步的入站请求,无论它们是否匹配Location。RequestHeader set Test "some_identifying_value"我通过向每个指令添加一个指令来测试这一点Location- 静态文件的 HTTP 请求和 for在它们上/api/socket/info有Test标头,但错误代理的 HTTP 请求上没有Test 标头,这表明它们被直接传递而没有由 Apache 指令处理。

最终,我的问题是:是否可以将任何版本的 Apache(我很高兴升级!)配置为反向代理基于 WebSocket 的应用程序,从而在 WebSocket 之后也正确地反向代理 HTTP 请求连接的?如果是这样,这是如何配置的?

reverse-proxy mod-proxy apache-2.4 websocket
  • 2 2 个回答
  • 12838 Views

2 个回答

  • Voted
  1. Best Answer
    Brian Beckett
    2017-04-28T07:45:54+08:002017-04-28T07:45:54+08:00

    安德斯的回答让我成功了 95%。

    基本场景:

    • 我们有一个服务器newapp.example.com
    • 8080 端口同时运行 HTTP 和 WebSockets
    • 响应 WebSockets 请求的 URL 是/api/socket/
    • 我们将此应用程序反向代理为http://apps.example.com/newapp/

    这是如何在一个<Location>块中为上述场景配置 WebSockets 和 HTTP 反向代理:

    <Location /newapp/>
        ProxyPass http://newapp.example.com:8080/
        ProxyPassReverse /
    
        RewriteEngine on
        RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
        RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
        RewriteRule /api/(.*) ws://newapp.example.com:8080/api/$1 [P]
    </Location>
    

    最终的重写规则至关重要——没有它,我们会将请求/newapp/api/socket传递给 WebSocket 服务器——它将被拒绝。

    正则表达式在之后解析所有内容api- 可能有更好的方法来捕获该块,但这有效。然后我们必须记住重新添加/api/到最终的重定向 URL。

    最重要的是,在 WebSocket 连接建立后,HTTP 请求继续工作!

    • 7
  2. anders
    2017-03-22T00:26:16+08:002017-03-22T00:26:16+08:00

    我在我的 spring boot 应用程序前面使用 apache 2.4 作为代理,这个应用程序提供一些 rest api 调用、websockets (sockjs) 和一些静态页面。我在让 websocket 工作时遇到了一些问题,秘密是添加你在下面看到的重写规则,现在它对我有用,我的 apache 虚拟主机配置如下所示:

    <VirtualHost *:443>
      SSLEngine on
      SSLCertificateFile /etc/httpd/ssl/my.crt
      SSLCertificateKeyFile /etc/httpd/ssl/my.key
      SSLCertificateChainFile /etc/httpd/ssl/intermediate.crt
      ProxyPreserveHost On
      ProxyPass / http://127.0.0.1:8080/
      ProxyPassReverse / http://127.0.0.1:8080/
      ProxyRequests Off
      RewriteEngine on
      RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
      RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
      RewriteRule .* ws://localhost:6868%{REQUEST_URI} [P]
      ServerName my.dnsname.com
    </VirtualHost>
    
    • 2

相关问题

  • 反向代理设备[关闭]

  • 清漆配置仅缓存未登录用户

  • Varnish 缓存如何处理不同的域?

  • Varnish 与其他反向代理

  • 内省 Varnish 的工具

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve