首页 > 解决方案 > “位置 0 处 JSON 中的意外令牌 H”SignalR Core 和 Apache Web 服务器上的 Kestrel

问题描述

我目前正在 Ubuntu 上运行 apache2 网络服务器。此 Web 服务器托管 Vue.js Web 应用程序,该应用程序使用 SignalR 连接到 .Net Core 应用程序(也在同一 linux 服务器上)以创建 websocket。

.Net Core 应用程序使用 Kestrel 运行。以下是将 domain.com/api 重新路由到在端口 5000 上运行的 .Net Core 应用程序的 apache 配置。

<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost _default_:443>
DocumentRoot /var/www/example.com/dist/spa
ServerName www.example.com
ServerAlias example.com

ProxyPreserveHost On
ProxyPass "/api" http://localhost:5000/
ProxyPassReverse "/api" http://localhost:5000/
RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
  RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
  RewriteRule /(.*) ws://localhost:5000/$1 [P]

SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:+MEDIUM:!LOW:!RC4
SSLCertificateFile /etc/apache2/ssl/example_com.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key
SSLCertificateChainFile /etc/apache2/ssl/example_com.ca-bundle

ErrorLog ${APACHE_LOG_DIR}example-error.log
CustomLog ${APACHE_LOG_DIR}example.log common
</VirtualHost>

当 Vue.js 应用程序尝试创建到 example.com/api/mainHub 的 websocket 连接时,会发生以下错误:

无法完成与服务器的协商:SyntaxError: Unexpected token H in JSON at position 0

它似乎将请求发送到正确的 URL,https://example.com/api/mainHub ,但无法建立连接。

我在 Linux 服务器上注意到的一件事是 POST 在路径中不包含 /api。

信息:Microsoft.AspNetCore.Hosting.Internal.WebHost[1] 请求开始 HTTP/1.1 POST http://example.com//mainHub/negotiate text/plain;charset=UTF-8 0

这是我的 apache2 配置如何将请求路由到 /api 目录的问题吗?

编辑 我已经更改了我的 apache 配置以删除/localhost:5000 末尾的额外内容 - 这允许外部连接到达正确的 API 路径。

<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost _default_:443>
DocumentRoot /var/www/example.com/dist/spa
ServerName www.example.com
ServerAlias example.com

RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
  RewriteRule /(.*) wss://localhost:5000$1 [P]
  RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
  RewriteRule /(.*) https://localhost:5000$1 [P]

ProxyPreserveHost On
ProxyPass "/api" http://localhost:5000
ProxyPassReverse "/api" http://localhost:5000

SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:+MEDIUM:!LOW:!RC4
SSLCertificateFile /etc/apache2/ssl/example_com.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key
SSLCertificateChainFile /etc/apache2/ssl/example_com.ca-bundle

ErrorLog ${APACHE_LOG_DIR}example-error.log
CustomLog ${APACHE_LOG_DIR}example.log common
</VirtualHost>

现在的问题似乎与安全 websocket 升级有关。我尝试将 ws 升级更改为 wss,但仍然有问题。当客户端尝试建立 wss 连接时,会出现以下错误:

WebSocket 连接到“wss://example.com/api/mainHub?id=k1-_KxspgAQgIAhKroQBpQ”失败:WebSocket 握手期间出错:意外响应代码:502

我认为我的虚拟主机使用 HTTPS 升级 websocket 连接的方式有问题。

错误:无法启动传输“WebSockets”:null

标签: apacheubuntu.net-coreasp.net-core-signalrkestrel

解决方案


如果您的 .Net Core 应用程序正在侦听/api/端口 5000,则将其添加到 ProxyPass 指令中:

ProxyPass "/api" http://localhost:5000/api
ProxyPassReverse "/api" http://localhost:5000/api

编辑:试试

RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
  RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
  RewriteRule /(.*) ws://localhost:5000/$1 [P]

ProxyPreserveHost On
ProxyPass "/api" http://localhost:5000
ProxyPassReverse "/api" http://localhost:5000

推荐阅读