【问题标题】:How to make BrowserSync work with an nginx proxy server?如何使 BrowserSync 与 nginx 代理服务器一起工作?
【发布时间】:2015-02-27 01:33:09
【问题描述】:

(如果需要,请参阅my last question 了解更多背景信息。)

我正在开发一个使用分离的前端和后端的应用程序:

  • 后端是一个主要提供 REST API 的 Rails 应用(在 localhost:3000 上提供服务)。
  • 前端是一个 AngularJS 应用程序,我正在使用 Gulp 构建它并在 localhost:3001 上本地提供服务(使用 BrowserSync)。

为了让两端相互通信,同时尊重same-origin policy,我配置了 nginx 作为两者之间的代理,在localhost:3002 上可用。这是我的 nginx.conf:

worker_processes 1;

events {
  worker_connections 1024;
}

http {
  include mime.types;
  default_type application/octet-stream;
  sendfile on;
  keepalive_timeout 65;

  server {
    listen 3002;
    root /;

    # Rails
    location ~ \.(json)$ {
      proxy_pass http://localhost:3000;
    }

    # AngularJS
    location / {
      proxy_pass http://localhost:3001;
    }
  }
}

基本上,任何对 .json 文件的请求,我都会发送到 Rails 服务器,而任何其他请求(例如,静态资产),我都会发送到 BrowserSync 服务器。

来自我gulpfile.coffee 的 BrowserSync 任务:

gulp.task 'browser-sync', ->
  browserSync
    server:
      baseDir: './dist'
      directory: true
    port: 3001
    browser: 'google chrome'
    startPath: './index.html#/foo'

这一切基本上都有效,但有几个我正在尝试解决的警告:

  • 当我运行 gulp 任务时,基于上述配置,BrowserSync 会在 http://localhost:3001/index.html#/foo 加载一个 Chrome 选项卡。但是,由于我使用的是 nginx 代理,因此我需要端口为 3002。有没有办法告诉 BrowserSync,“在端口 3001 上运行,但在端口 3002 上启动”?我尝试为startPath 使用绝对路径,但它只需要相对路径。
  • 每次 BrowserSync 启动时,我都会在控制台中收到一个(看似良性的)JavaScript 错误:WebSocket connection to 'ws://localhost:3002/browser-sync/socket.io/?EIO=3&transport=websocket&sid=m-JFr6algNjpVre3AACY' failed: Error during WebSocket handshake: Unexpected response code: 400。不确定这到底是什么意思,但我的假设是 BrowserSync 被 nginx 代理弄糊涂了。

如何解决这些问题以使其无缝运行?

感谢您的任何意见!

【问题讨论】:

    标签: nginx proxy gulp same-origin-policy browser-sync


    【解决方案1】:

    设置浏览器同步以使用通过 websocket 在 uwsgi 上运行的 python (django) 应用程序。 Django 应用程序以 /app 为前缀,以生成类似于 http://example.com/app/admin/ 的 url

    server {
      listen 80;
      server_name example.com;
    
      charset utf-8;
    
      root /var/www/example/htdocs/static;
      index index.html index.htm;
    
      try_files $uri $uri/ /index.html?$args;
    
      location /app {
        ## uWSGI setup
        include     /etc/nginx/uwsgi_params;
        uwsgi_pass  unix:///var/run/example/uwsgi.sock;
        uwsgi_param SCRIPT_NAME /app;
        uwsgi_modifier1 30;
      }
    
      location /media  {
        alias /var/www/example/htdocs/storage;
      }
    
      location /static {
        alias /var/www/example/htdocs/static;
      }
    
    }
    

    【讨论】:

      【解决方案2】:

      您也可以从 gulp/browsersync 端非常简单地使用它的proxy option

      gulp.task('browser-sync', function() {
          browserSync({
              ...
              proxy: 'localhost:3002'
          });
      });
      

      这意味着你的浏览器像往常一样通过 gulp 直接连接到 browsersync,除了现在它代理 nginx。只要您的前端没有在 URL 中硬编码主机/端口,对 Rails 的请求将通过代理并具有相同的来源,因此您仍然可以 POST 等。这对于某些人来说可能是可取的,因为开发设置的这种更改是在代码的开发部分(gulp+browsersync)而不是条件化/更改也在生产中运行的 nginx 配置。

      【讨论】:

      • 确实如此。这就够了!
      【解决方案3】:

      我只有将/browser-sync/socket.io 附加到proxy_pass url 才能成功。

      map $http_upgrade $connection_upgrade {
          default upgrade;
          '' close;
      }
      
      server {
          # ...
      
          # BrowserSync websocket
          location /browser-sync/socket.io/ {
              proxy_pass http://localhost:3001/browser-sync/socket.io/;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "Upgrade";
          }
      }
      

      【讨论】:

      • 刚发现proxy_pass http://localhost:3001/proxy_pass http://localhost:3001不一样。使用proxy_pass http://localhost:3001,会自动附加位置部分。
      【解决方案4】:

      要更好地控制页面的打开方式,请使用opn 而不是浏览器同步机制。像这样的东西(在 JS 中 - 抱歉,我的 Coffee Script 有点生疏了):

      browserSync({
          server: {
              // ...
          },
          open: false,
          port: 3001
      }, function (err, bs) {
          // bs.options.url contains the original url, so
          // replace the port with the correct one:
          var url = bs.options.urls.local.replace(':3001', ':3002');
          require('opn')(url);
          console.log('Started browserSync on ' + url);
      });
      

      我对 Nginx 不熟悉,但是根据this page 的说法,第二个问题的解决方案可能是这样的:

      map $http_upgrade $connection_upgrade {
          default upgrade;
          '' close;
      }
      
      server {
          # ...
      
          # BrowserSync websocket
          location /browser-sync/socket.io/ {
              proxy_pass http://localhost:3001;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "Upgrade";
          }
      }
      

      【讨论】:

      • 非常感谢!这很好用。我不得不做一些小的调整 - (a) 在 gulpfile 中,通过属性 bs.options.urls.local 而不是 bs.options.url 访问 url(看起来 API 可能略有变化?),以及 (b) 在 nginx 中。 conf,将 BrowserSync proxy_pass 设置为 http://localhost:3001 而不是 http://localhost:3002 (我假设这是为了指定 BrowserSync 服务器,而不是 nginx 代理)。再次感谢您的时间和帮助 - 他们非常感谢!
      猜你喜欢
      • 2012-04-27
      • 1970-01-01
      • 2014-08-16
      • 1970-01-01
      • 2019-07-27
      • 1970-01-01
      • 2020-07-20
      • 1970-01-01
      • 2016-10-22
      相关资源
      最近更新 更多