WebSocket协商失败时各种返回值

linux admin 2年前 (2023-04-12) 682次浏览 0个评论

介绍

前几天墙又双叒叕发威了,小白一直ws裸奔的一台小鸡也被墙了,就又看了下文档,发现里面提到这么一点:

  if ($http_upgrade != "websocket") { # WebSocket协商失败时返回404
        return 404;
    }

那也就是说,在不不使用TLS协议的前提下(当然你应该使用……),ws路径是透明的,没有任何加密的,我们直接使用浏览器访问IP/域名+路径时会返回404错误代码,如下图所示:

根据小白的观察,大多数人要么时连nginx都没有直接返回Bad Request,或者时前置了一个nginx,则返回404,那如果我们不返回404,而返回一个真实的网页,或者返回一个反代的网页,是否会看起来更正常,我也不知道这个想法对不对,就顺着往下写了。

返回404错误代码

  if ($http_upgrade != "websocket") { # WebSocket协商失败时返回404
        return 404;
    }

这是一个 Nginx 配置片段,用于处理 WebSocket 请求。让我们来逐行解释:

  1. if ($http_upgrade != "websocket") {:这行代码检查 HTTP 请求头中的 Upgrade 字段是否等于 “websocket”。$http_upgrade 是一个变量,代表 HTTP 请求头中的 Upgrade 字段。如果该字段的值不是 “websocket”,则满足条件,执行括号中的代码。
  2. return 404;:当满足 if 条件时,这行代码会使 Nginx 返回一个 404 状态码,表示请求的资源未找到。换句话说,如果请求不是 WebSocket 请求,服务器将返回 404 错误。
  3. }:结束 if 语句块。

总结一下,这个 Nginx 配置片段的意思是:如果请求的协议不是 WebSocket(即请求头中的 Upgrade 字段不等于 “websocket”),则返回 404 错误。这可以确保仅处理 WebSocket 请求,而忽略其他类型的请求。

返回其他值

在 Nginx 配置中,你可以使用 return 指令返回其他的 HTTP 状态码和相应的信息。以下是一些示例:

  1. 返回 403 禁止访问:
    if ($http_upgrade != "websocket") {
        return 403;
    }
    
  2. 返回 400 错误请求:
    if ($http_upgrade != "websocket") {
        return 400;
    }
    
  3. 返回 500 服务器内部错误:
    if ($http_upgrade != "websocket") {
        return 500;
    }
    
  4. 返回自定义状态码和消息:
    if ($http_upgrade != "websocket") {
        return 418 "I'm a teapot";
    }
    

在这些示例中,你可以将 403、400、500 或 418 等状态码替换为你想要的任何有效的 HTTP 状态码。同样,你可以自定义返回的消息,只需将其放在双引号中即可。

需要注意的是,在实际应用中,应当根据实际情况选择合适的状态码。例如,如果请求格式不正确,可以返回 400(错误请求);如果请求被拒绝,可以返回 403(禁止访问)等。

返回一个网页

当然可以。在 Nginx 配置中,你可以使用 error_page 指令来指定一个自定义的错误页面。这样,当满足某个条件时,Nginx 将返回指定的错误页面。下面是一个示例:

首先,在 Nginx 配置文件的 server 块中添加以下配置:

error_page 418 /custom_error_page.html;

location = /custom_error_page.html {
    root /path/to/your/error_pages;
    internal;
}

if ($http_upgrade != "websocket") {
    return 418;
}

这个配置的说明如下:

  1. error_page 418 /custom_error_page.html;:为 HTTP 状态码 418 指定一个自定义错误页面,该页面的 URI 为 /custom_error_page.html
  2. location = /custom_error_page.html { ... }:定义一个 location 块来处理 /custom_error_page.html 路径的请求。
  3. root /path/to/your/error_pages;:指定自定义错误页面所在的目录。你需要将 /path/to/your/error_pages 替换为实际的目录路径。
  4. internal;:这个指令表明此 location 块仅用于内部处理,不能直接通过外部请求访问。
  5. if ($http_upgrade != "websocket") { ... }:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。
  6. return 418;:如果请求不是 WebSocket 请求,返回 418 状态码。由于我们之前为状态码 418 指定了自定义错误页面,Nginx 将返回该错误页面。

请确保创建一个名为 custom_error_page.html 的 HTML 文件,并将其放在你指定的错误页面目录(/path/to/your/error_pages)中。当请求不是 WebSocket 请求时,Nginx 将返回这个自定义错误页面。你可以根据需要修改状态码和错误页面的文件名。

返回一个反代的网站

你可以在 Nginx 配置中设置反向代理,当满足特定条件时(如本例中的非 WebSocket 请求),将请求代理到另一个网站。以下是一个配置示例:

upstream backend {
    server backend.example.com;
}

if ($http_upgrade != "websocket") {
    rewrite ^(.*)$ /proxy$1 last;
}

location /proxy {
    proxy_pass http://backend;
    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;
}

这个配置的说明如下:

  1. upstream backend { ... }:定义一个名为 backend 的上游服务器组。
  2. server backend.example.com;:将 backend.example.com 作为上游服务器。你可以将其替换为你要代理的目标服务器地址。
  3. if ($http_upgrade != "websocket") { ... }:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。
  4. rewrite ^(.*)$ /proxy$1 last;:如果请求不是 WebSocket 请求,将 URI 重写为以 /proxy 开头,并将原始 URI 附加在其后,然后跳转到下一个 location 块进行处理。
  5. location /proxy { ... }:定义一个 location 块,用于处理以 /proxy 开头的请求。
  6. proxy_pass http://backend;:将请求代理到之前定义的 backend 上游服务器组。
  7. proxy_set_header ...:这些指令用于设置代理请求的 HTTP 头。这里设置了 HostX-Real-IPX-Forwarded-ForX-Forwarded-Proto 头,以便后端服务器能获取正确的客户端信息。

当请求不是 WebSocket 请求时,Nginx 将请求反向代理到指定的后端服务器。请注意,这个配置仅作为示例,你可能需要根据实际需求调整配置。

比方说我们要返回 http://209.222.11.49:2333 这个网页。要将非 WebSocket 请求反向代理到 http://209.222.11.49:2333,请按照以下示例配置 Nginx:

if ($http_upgrade != "websocket") {
    rewrite ^(.*)$ /proxy$1 last;
}

location /proxy {
    proxy_pass http://209.222.11.49:2333;
    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;

    # 将 /proxy 前缀去掉,避免向后端服务器传递这个前缀
    rewrite ^/proxy(/.*)$ $1 break;
}

这个配置的说明如下:

  1. if ($http_upgrade != "websocket") { ... }:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。
  2. rewrite ^(.*)$ /proxy$1 last;:如果请求不是 WebSocket 请求,将 URI 重写为以 /proxy 开头,并将原始 URI 附加在其后,然后跳转到下一个 location 块进行处理。
  3. location /proxy { ... }:定义一个 location 块,用于处理以 /proxy 开头的请求。
  4. proxy_pass http://209.222.11.49:2333;:将请求代理到指定的 IP 地址和端口(209.222.11.49:2333)。
  5. proxy_set_header ...:这些指令用于设置代理请求的 HTTP 头。这里设置了 HostX-Real-IPX-Forwarded-ForX-Forwarded-Proto 头,以便后端服务器能获取正确的客户端信息。
  6. rewrite ^/proxy(/.*)$ $1 break;:将请求中的 /proxy 前缀去掉,以避免向后端服务器传递这个前缀。

当请求不是 WebSocket 请求时,Nginx 将请求反向代理到指定的 IP 地址和端口。请注意,这个配置仅作为示例,你可能需要根据实际需求调整配置。

要将非 WebSocket 请求反向代理到 https://www.kernel.org,请按照以下示例配置 Nginx:

if ($http_upgrade != "websocket") {
    rewrite ^(.*)$ /proxy$1 last;
}

location /proxy {
    proxy_pass https://www.kernel.org;
    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;

    # 将 /proxy 前缀去掉,避免向后端服务器传递这个前缀
    rewrite ^/proxy(/.*)$ $1 break;

    # 添加 SSL 代理设置
    proxy_ssl_server_name on;
    proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    proxy_ssl_session_reuse on;
}

这个配置的说明如下:

  1. if ($http_upgrade != "websocket") { ... }:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。
  2. rewrite ^(.*)$ /proxy$1 last;:如果请求不是 WebSocket 请求,将 URI 重写为以 /proxy 开头,并将原始 URI 附加在其后,然后跳转到下一个 location 块进行处理。
  3. location /proxy { ... }:定义一个 location 块,用于处理以 /proxy 开头的请求。
  4. proxy_pass https://www.kernel.org;:将请求代理到指定的 HTTPS 网址(https://www.kernel.org)。
  5. proxy_set_header ...:这些指令用于设置代理请求的 HTTP 头。这里设置了 HostX-Real-IPX-Forwarded-ForX-Forwarded-Proto 头,以便后端服务器能获取正确的客户端信息。
  6. rewrite ^/proxy(/.*)$ $1 break;:将请求中的 /proxy 前缀去掉,以避免向后端服务器传递这个前缀。
  7. proxy_ssl_server_name on;:启用 SNI(Server Name Indication)扩展,以便在 SSL 握手期间发送正确的服务器名称。
  8. proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;:设置允许的 SSL 协议版本。这里允许 TLSv1、TLSv1.1 和 TLSv1.2。
  9. proxy_ssl_session_reuse on;:启用 SSL 会话复用,以提高性能。

当请求不是 WebSocket 请求时,Nginx 将请求反向代理到指定的 HTTPS 网址。请注意,这个配置仅作为示例,你可能需要根据实际需求调整配置。

要将非 WebSocket 请求反向代理到 https://kernel.ubuntu.com/~kernel-ppa,请按照以下示例配置 Nginx:

if ($http_upgrade != "websocket") {
    rewrite ^(.*)$ /proxy$1 last;
}

location /proxy {
    proxy_pass https://kernel.ubuntu.com/~kernel-ppa;
    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;

    # 将 /proxy 前缀去掉,避免向后端服务器传递这个前缀
    rewrite ^/proxy(/.*)$ $1 break;

    # 添加 SSL 代理设置
    proxy_ssl_server_name on;
    proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    proxy_ssl_session_reuse on;
}

这个配置的说明如下:

  1. if ($http_upgrade != "websocket") { ... }:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。
  2. rewrite ^(.*)$ /proxy$1 last;:如果请求不是 WebSocket 请求,将 URI 重写为以 /proxy 开头,并将原始 URI 附加在其后,然后跳转到下一个 location 块进行处理。
  3. location /proxy { ... }:定义一个 location 块,用于处理以 /proxy 开头的请求。
  4. proxy_pass https://kernel.ubuntu.com/~kernel-ppa;:将请求代理到指定的 HTTPS 网址(https://kernel.ubuntu.com/~kernel-ppa)。
  5. proxy_set_header ...:这些指令用于设置代理请求的 HTTP 头。这里设置了 HostX-Real-IPX-Forwarded-ForX-Forwarded-Proto 头,以便后端服务器能获取正确的客户端信息。
  6. rewrite ^/proxy(/.*)$ $1 break;:将请求中的 /proxy 前缀去掉,以避免向后端服务器传递这个前缀。
  7. proxy_ssl_server_name on;:启用 SNI(Server Name Indication)扩展,以便在 SSL 握手期间发送正确的服务器名称。
  8. proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;:设置允许的 SSL 协议版本。这里允许 TLSv1、TLSv1.1 和 TLSv1.2。
  9. proxy_ssl_session_reuse on;:启用 SSL 会话复用,以提高性能。

当请求不是 WebSocket 请求时,Nginx 将请求反向代理到指定的 HTTPS 网址。请注意,这个配置仅作为示例,你可能需要根据实际需求调整配置。

结语

小白不知道这样的设置有没有用,是否属于掩耳盗铃,还有懂得大佬不吝赐教。


VPS小白 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:WebSocket协商失败时各种返回值
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址