javascript - 通过 Apache/Varnish 的 Websocket 失败

标签 javascript apache websocket varnish ratchet

几天来,我一直试图让这个与 websocket 的连接正常工作,但是当我尝试通过 Javascript 连接到它时,我仍然遇到错误。

javascript抛出的错误如下:

WebSocket connection to 'ws://lmc-staging.mydomain.org:8081/' failed: Connection closed before receiving a handshake response
brainsocket.min.js:1 Event {clipboardData: undefined, path: NodeList[0], cancelBubble: false, returnValue: true, srcElement: WebSocket…}bubbles: false cancelBubble: false cancelable: false clipboardData: undefined currentTarget: WebSocket defaultPrevented: false eventPhase: 0path: NodeList[0] returnValue: true srcElement: WebSockettarget: WebSockettimeStamp: 1421938720697 type: "error"__proto__: Event

brainsocket.min.js:1 WebSocket is already in CLOSING or CLOSED state.

请求是 piped将 Varnish 用于 Apache 网络服务器 (xxx.xxx.xxx.203)。 Varnish 配置发布如下:
# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
# 
# Default backend definition.  Set this to point to your content
# server.
# 

# Internal hosts; same as purge, but separated for clarity.
acl internal {
  "localhost";
  "127.0.0.1";
  "xxx.xxx.xxx.0"/24;
  "xxx.xxx.xxx.203";
  "xxx.xxx.xxx.204";
}

# Hosts allowed to purge cache
acl purge {
  "localhost";
  "127.0.0.1";
  "xxx.xxx.xxx.0"/24;
  "xxx.xxx.xxx.203";
  "xxx.xxx.xxx.204";
}

# DEV webserver
backend vsrv1474 {
  .host = "xxx.xxx.xxx.203";
  .port = "80";
  .connect_timeout = 300s;
  .first_byte_timeout = 300s;
  .between_bytes_timeout = 300s;
}

# DEV brainsocket
backend brainsocket {
  .host = "xxx.xxx.xxx.203";
  .port = "8081";
  .connect_timeout = 300s;
  .first_byte_timeout = 300s;
  .between_bytes_timeout = 300s;
}

# PROD webserver
backend vsrv1475 {
  .host = "xxx.xxx.xxx.204";
  .port = "80";
  #.connect_timeout = 5s;
  #.first_byte_timeout = 60s;a
  #.between_bytes_timeout = 60s;
  .connect_timeout = 300s;
  .first_byte_timeout = 300s;
  .between_bytes_timeout = 300s;
}


sub vcl_recv {
  # Allow purge from hosts in purge acl or return 405
  if (req.request == "PURGE") {
    if (!client.ip ~ purge) {
      error 405 "Not allowed";
    }
    return(lookup);
  }


# entry for brainsocket
  if (req.http.Upgrade ~ "(?i)websocket") {
    set req.backend = brainsocket;
    return (pipe);
  }

# end entry for brainsocket

  if (req.url ~ "/dev/" || req.http.host == "staging.mydomain.org" || req.http.host == "dev.mydomain2.org" || req.http.host == "lmc-staging.mydomain.org" ){
    set req.backend = vsrv1474;
    return(pass);
  } elsif ( req.http.host == "www.mydomain2.org" || req.http.host == "lmc.mydomain2.org" ) {
    set req.backend = vsrv1475;
  } else {
    set req.backend = vsrv1475;
  }


  if (req.url ~ "^/misc/progress\.js\?[0-9]+$") {
    set req.url = "/misc/progress.js";
  }

  if (req.url ~ "^/admin/content/backup_migrate/export") {
    return (pipe);
  }

  # Do not cache these paths.
  if(req.url ~ "^/status\.php$"||
      req.url ~ "^/update\.php$"||
      req.url ~ "^/install\.php" ||
      req.url ~ "^/admin" ||
      req.url ~ "^/admin/.*$"||
      req.url ~ "^/user" ||
      req.url ~ "^/user/.*$" ||
      req.url ~ "^/users/.*$" ||
      req.url ~ "^/info/.*$" ||
      req.url ~ "^/flag/.*$"||
      req.url ~ "^.*/ajax/.*$"||
      req.url ~ "^.*/facebook-rss.xml$" ||
      req.url ~ "^.*/twitter-rss.xml$" ||
      req.url ~ "^.*/ahah/.*$") {
      return(pass);
  }

  # Disallow outside access to cron.php or install.php
  if (req.url ~ "^/(cron|install)\.php$" && !client.ip ~ internal) {
    error 404 "Page not found.";
  }

  # Always cache the following file types for all users.
  if (req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|woff)(\?[a-z0-9]+)?$") {
    unset req.http.Cookie;
  }

  # Remove all cookies that Drupal doesn't need to know about. ANY remaining
  # cookie will cause the request to pass-through to Apache. For the most part
  # we always set the NO_CACHE cookie after any POST request, disabling the
  # Varnish cache temporarily. The session cookie allows all authenticated users
  # to pass through as long as they're logged in.
  if (req.http.Cookie) {
    set req.http.Cookie = ";" + req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    set req.http.Cookie = regsuball(req.http.Cookie, ";(S{1,2}ESS[a-z0-9]+|NO_CACHE|CI_SESSION|ci_session|token|PHPSESSID)=", "; \1=");
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {
      # If there are no remaining cookies, remove the cookie header. If there
      # aren't any cookie headers, Varnish's default behavior will be to cache
      # the page.
      unset req.http.Cookie;
    }
    else {
      # If there is any cookies left (a session or NO_CACHE cookie), do not
      # cache the page. Pass it on to Apache directly.
      return (pass);
    }
  }


  # Remove the "has_js" cookie
  set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");

  # Remove the "Drupal.toolbar.collapsed" cookie
  set req.http.Cookie = regsuball(req.http.Cookie, "Drupal.toolbar.collapsed=[^;]+(; )?", "");

  # Remove any Google Analytics based cookies
  set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", "");

  # Remove the Quant Capital cookies (added by some plugin, all __qca)
  set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");

  # Are there cookies left with only spaces or that are empty?
  if (req.http.cookie ~ "^ *$") {
    unset req.http.cookie;
  }

  # Cache static content unique to the theme (so no user uploaded images)
  if (req.url ~ "^/themes/" && req.url ~ ".(css|js|png|gif|jp(e)?g)") {
    unset req.http.cookie;
  }

}


sub vcl_pipe {
    #copy the upgrade header
    if (req.http.upgrade) {
        set bereq.http.upgrade = req.http.upgrade;
    }

    #closing the connection might be necessary for some applications as the connection will remain open forever and consume resources if not properly stopped by server or client
    #set bereq.http.Connection = "close";
}


sub vcl_miss {
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged";
  }
}

sub vcl_hit {
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged";
  }
}

sub vcl_fetch {
  unset beresp.http.Vary;
  set beresp.http.x-url = req.url;
  set beresp.http.x-host = req.http.host;

 # Don't allow static files to set cookies.
  if (req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm)(\?[a-z0-9]+)?$") {
    # beresp == Back-end response from the web server.
    unset beresp.http.set-cookie;
  }

  # Check if no ttl and a cookie set. 
  if (beresp.ttl <= 0s && beresp.http.Cookie ~ ".+" ) {
    set beresp.http.X-Cacheable = "NO:Not Cacheable: No ttl; has cookie";
  # Varnish determined the object was not cacheable
  } elsif (beresp.ttl <= 0s) {
    set beresp.http.X-Cacheable = "NO:Not Cacheable: No ttl; no cookie";
  # You don't wish to cache content for logged in users
  } elsif (req.http.Cookie ~ "(S{1,2}ESS[a-z0-9]+|NO_CACHE|CI_SESSION|ci_session|token|PHPSESSID)") {
    set beresp.http.X-Cacheable = "NO:Got Session";
    return(hit_for_pass);

    # You are respecting the Cache-Control=private header from the backend
  } elsif (beresp.http.Cache-Control ~ "private") {
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    return(hit_for_pass);

  # Varnish determined the object was cacheable
  } else {
    set beresp.http.X-Cacheable = "YES";
  }

  return(deliver);
}

sub vcl_deliver {
  if (obj.hits > 0) {
     set resp.http.X-Cache = "HIT";
  } else {
    set resp.http.X-Cache = "MISS";
  }
  unset resp.http.x-url; # Optional
  unset resp.http.x-host; # Optional
  unset resp.http.Server;
  unset resp.http.X-Generator;
  unset resp.http.X-Powered-By;
  unset resp.http.X-Drupal-Cache;
}

我正在使用 Brainsocket 包,它允许您使用 Laravel 创建客户端和服务器端套接字。 Brainsocket 使用 Ratchet 作为其底层 websocket 层。

最佳答案

问题是(正如 Marcel Dumont 建议的)与 Varnish 未配置为监听端口 8081 的事实有关。因此,我们重定向前端客户端以连接端口 80,并依靠 Varnish 将信息通过管道传递到底层 websocket端口 8081。

关于javascript - 通过 Apache/Varnish 的 Websocket 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28093005/

相关文章:

javascript - jQuery:当绑定(bind)/单击事件用于类时引用调用对象(this)

javascript - 使用复选框在 Google Fusion Tables 中进行过滤

apache - Apache白名单反向代理

php - 调试 Drupal 的白屏死机?

node.js - WebSocket通过Amazon ELB或直接通过WebSocket(远程IP问题)

javascript - 如何在nodejs中发送响应错误代码

javascript - 如何使多个 Collapse 处于动态状态

ruby-on-rails-3 - Dragonfly - 上传的图片不显示

nginx - Nginx 背后的 SignalR - 获得 200 响应而不是 websocket 升级

node.js - NodeJS WebSockets (ws) 模块是否实现了背压?