多个Vue.js站点 / NGINX反向代理 / 热重载不起作用

4

我目前正在本地开发多个Vue.js单页应用程序,并在尝试将这些应用程序服务放在NGINX反向代理后遇到了各种问题。具体来说,我遇到了许多与Websockets或sockjs-node相关的错误,这会破坏vue应用程序的热重载功能(404 Not Found)。

这些SPA中的每一个都在自己的基本Node.js服务器上运行,该服务器在其服务器根目录下提供静态文件。他们应该通过NGINX反向代理访问:

http://localhost:6200/ -> http://localhost/my-app1/
http://localhost:6205/ -> http://localhost/my-app2/
http://localhost:6210/ -> http://localhost/my-app3/

对于开发,我使用npm run serve运行所有vue.js应用程序,然后通过NGINX代理访问这些站点:http://localhost/my-appX/。这些站点没有任何功能问题,但热重载不起作用。

在浏览器的开发者控制台中查看后,有众多GET请求的EG: http://localhost/sockjs-node/info?t=1605955915882。显然,这个URL是错误的,因为我们当前是通过代理访问网站 - 我原本希望看到http://localhost/my-appX/sockjs-node/info?t=1605955915882。以下是在尝试使其工作之前我的当前配置:

我的NGINX配置:

upstream nodefrontend_myapp1 {
    server localhost:6200;
}
upstream nodefrontend_myapp2 {
    server localhost:6205;
}
upstream nodefrontend_myapp3 {
    server localhost:6210;
}

# Redirect HTTP to HTTPS
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    
    # 307 temporary redirect
    return 307 https://$host$request_uri; 
}

# HTTPS Proxy
server {
    listen 443 ssl http2;
    server_name localhost;
  
    # Proxy "my-app" URI traffic to correct server
    location /my-app1/ {
        proxy_buffering off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # For websockets
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";

        # Proxy to my-app's root
        proxy_pass http://nodefrontend_myapp1/;
    }

    # Note: several other sites are running via the below routes
    location /my-app2/ {
      proxy_pass http://nodefrontend_myapp2/;
      # ...
    }

    location /my-app3/ {
      proxy_pass http://nodefrontend_myapp3/;
      # ...
    }
}

vue.config.js配置:

module.exports = {
    // options...

    // I want the site to be accessible *RELATIVE* to the current URL.
    // This will make vue.js resources have no leading slash, eg: <link> href="css/file123.css" </link>
    // And should allow me to fetch resources on the current VHOST: eg: http://localhost/my-app/css/file123.css
    publicPath: "",
    
    devServer: {
        //disableHostCheck: true,
        https: false,
        public: "0.0.0.0",
        host: "localhost" ,
        port: 6200,
        sockPath: "", /////////// This has been causing me issues

    },

}

查看了webpack文档后,我发现应该在每个应用的vue.config.js中更新sockPath,于是我这样做了:

sockPath: "/my-appX/sockjs-node",

这样停止了 sockjs-node 的 404 GET 错误,但是现在出现了不同的错误,关于 websockets 找不到资源: ws://localhost/my-appX/sockjs-node/147/0dj5ee1p/websocket
为了检查问题是 webserver 还是 NGINX,我运行了 wscat -c ws://localhost:6200/my-appX/sockjs-node/147/0dj5ee1p/websocket,它确实工作了。这表明 NGINX 在某种程度上杀死了 websocket。为了再次确认,我通过 NGINX 测试了 websocket:wscat -c ws://localhost/my-appX/sockjs-node/147/0dj5ee1p/websocket,这次测试却没有成功。
经过几个小时的配置和 NGINX 玩耍,我在网上找到一篇文章,说我应该更改我的 NGINX proxy_pass URL,以删除结尾的斜杠。我将它从以下内容更改为:
proxy_pass http://nodefrontend_myappX/;

转化为:

proxy_pass http://nodefrontend_myappX;

通过wscat -c ws://localhost/my-appX/sockjs-node/147/0dj5ee1p/websocket重新测试了websocket,它正常工作了!但是…在去掉前导斜杠后,网站无法加载。我的怀疑是vue.config.js的publicPath,但我束手无策。

有没有人能够在NGINX反向代理(作为虚拟主机)后运行多个Vue.js站点,并使热重载功能正常工作?

====== 我找到了一个解决方案,但我不喜欢它:

  • 在服务器上以子路由的形式静态托管SPA:http://localhost:6200/my-app
  • 将NGINX反向代理_pass转到:proxy_pass http://localhost:6200/my-app/
  • 将vue.config.js文件的publicPath设置为:publicPath: "/my-app"
  • 不要设置vue.config.js的sockPath属性(删除它)。

这种配置的关键在于vue.js前端浏览器知道它位于/my-app,在/my-app上托管服务器发送请求,而NGINX实际上并不修改任何URI。

尽管此配置可行,但我不喜欢Web服务器必须在子路由上托管静态文件,且浏览器必须知道其vhost(publicPath) - 除非这是标准做法?对于浏览器了解它的publicPath (/my-appX/),我有点满意,因为它需要使用历史记录模式。

PS. 在生产中,我的原始配置使用相对publicPath正常工作。只是HRM在开发中出错了。

有人能够解决这个问题吗? 谢谢

========= 更新1)找到解决方法,不确定这是否是唯一的解决方法。

我发现我的vue.config.js devserver "public"属性设置不正确。根据webpack devserver文档,运行在浏览器中的devserver客户端(/sockjs-node)代码将通过查看其window.location变量来“猜测”服务器的位置。但是,由于我通过代理访问服务器,似乎默认情况下无法处理它。所以他们的解决方案是设置"public"属性,使客户端直接与服务器通信(跨域请求)...如果你问我的话,这有点儿hack。

因此,客户端sockjs-node现在直接从http://localhost/my-appX/到http://lcoalhost:62xx/进行通信。

这就是(例如)my-app1的vue.config.js现在的样子:

module.exports = {
    // options...

    publicPath: "",
    
    devServer: {
        //disableHostCheck: true,
        https: false,
        public: "localhost:6200",  //// This line makes the client browser talk DIRECTLY to this address / server for hot reloading.
        host: "0.0.0.0" ,
        port: 6200,

    },

}

话虽如此,现在通过http一切都按预期工作。但是,将NGINX更新为https会导致webpack-devserver sockjs-node出现CORS错误。这是因为客户端/浏览器已升级到HTTPS,但webpack-devserver仅支持http。然而,为了解决这个问题,我只需将vue.config.js devserver设置为https,CORS错误就消失了。

这似乎更像是与webpack-devserver sockjs-node的问题/限制,而不是stackoverflow问题。将问题留在此处。


一般来说,设计良好的应用程序应该允许其在应用程序设置下可以指定的任何前缀下使用。然而,由于Vue应用程序是单页面应用程序,因此可能会有某种解决方法。您可以检查其中一个失败的请求并告诉我,该请求是否具有“Referer” HTTP请求标头? - Ivan Shatsky
1个回答

3

如果你想保留热重载功能(不确定你是否需要),你需要添加一个类似于这样的位置。

location /sockjs-node {
    proxy_pass http://nodefrontend_myapp;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

1
啊,抱歉 - 我编辑了原始的NGINX配置文件。但是,我想保持热重载功能。然而,如果我只有一个反向代理,你的解决方案就可以了。(如果我错了,请纠正我)- 我有很多反向代理,每个代理都转发到一个vue.js服务器(请参见更新的NGINX)。这意味着每个站点(在浏览器中)都会发送:http://localhost/sockjs-node,而NGINX不知道要将其路由到哪个服务器,对吗? - g-radam
查看已编辑的答案,代理到上游,然后这个解决方案完美运行。 - C.Gochev
没错,我同意这个方案可以百分之百地运行,我已经测试过了,但这并不是我的问题的直接源头。如果我只有一个单一的SPA服务器(将index.html托管在根目录下),和一个单一的反向代理(将上游路由到服务器根目录),那么这个NGINX配置就非常好用。问题在于VHOST部分——每个服务器都有自己的路由,例如: location /my-app1/ { proxy_pass http://frontend_myapp1; ... } location /my-app2/ { proxy_pass http://frontend_myapp2; ... } 仅仅在服务器路由前加上/my-app1/或/my-app2/就会对热重载造成混乱。 - g-radam
你尝试过省略proxy_pass行并从vue.config中删除sockPaths,以便它适用于已进行更改的任何应用程序吗? - C.Gochev
我也尝试了那个,但没有产生任何结果。顺便说一句,我想我找到了问题的根源 - 请看我的更新。但我认为这是 sockjs-node / webpack-devserver 的限制。 - g-radam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接