1. 背景:https和wss这两个协议的关系自行百度,结论:https 加上特定的请求头,就会升级为wss请求

  1. 有人会杠:这个功能nginx已经实现:比如如下配置:

proxy_ssl_certificate     /opt/required/nginx/ssl/k8s-server.crt;
proxy_ssl_certificate_key /opt/required/nginx/ssl/k8s-server.key;

location /wss/ {
    proxy_pass https://k8s.test.com:6443/apis/subresources.kubevirt.io/v1/namespaces/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Real-IP $remote_addr;
}

优点:不需要做配置,可以直接将请求代理到wss

缺点:不能对接口进行鉴权,换环境就需要换证书

因此:需要用代码实现 nginx 对应配置的功能

  1. go语言实现

使用 gorilla,相对来说比较简单,go提供了特别强大的功能,因此就不写了(有需要留言,我给你写),下面着重写一下使用java如何实现

  1. java实现

前置条件:

  • 使用okhttp

  • 使用kubernetes的client-java(原理和步骤类似,因为我们项目使用java做k8s的二开,所以我的例子也是用的k8s client-java sdk)

代码:

import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Pair;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;

public class Test {
  public static final String WEBSOCKET = "websocket";
  public static final String CONNECTION = "Connection";
  public static final String UPGRADE = "Upgrade";

  public static void main(String[] args) throws IOException, ApiException {
    String config = "你自己的k8s config文件的内容";
    HashMap<String, String> headers = new HashMap<String, String>();
    // https请求升级为wss
    headers.put(CONNECTION, UPGRADE);
    headers.put(UPGRADE, WEBSOCKET);
    String[] localVarAuthNames = new String[] {"BearerToken"};
    // 如下是使用k8s 创建的request,如果需要其他方式创建requst也是可以的,可以自行百度一下,
    // 如何使用java 发送 https请求
    ApiClient client = ClientBuilder.kubeconfig(
            KubeConfig.loadKubeConfig(new BufferedReader(new StringReader(config))))
            .build();
    Request request =
        client.buildRequest(
            "/apis/subresources.kubevirt.io/v1/namespaces/vm/virtualmachineinstances/centos/vnc",
            "GET",
            new ArrayList<Pair>(),
            new ArrayList<Pair>(),
            null,
            headers,
            new HashMap<String, String>(),
            new HashMap<String, Object>(),
            localVarAuthNames,
            null);
    WebSocket webSocket =
        client
            .getHttpClient()
            .newWebSocket(
                request,
                new WebSocketListener() {
                  @Override
                  public void onClosed(
                      @NotNull WebSocket webSocket, int code, @NotNull String reason) {
                    super.onClosed(webSocket, code, reason);
                  }

                  @Override
                  public void onClosing(
                      @NotNull WebSocket webSocket, int code, @NotNull String reason) {
                    super.onClosing(webSocket, code, reason);
                  }

                  @Override
                  public void onFailure(
                      @NotNull WebSocket webSocket,
                      @NotNull Throwable t,
                      @Nullable Response response) {
                    super.onFailure(webSocket, t, response);
                  }

                  // 收到文本数据
                  @Override
                  public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {
                    System.out.println("onMessage with text:" + text);

                  }

                  // 收到二进制数据
                  // 至于文本数据和二进制数据哪个收到,要看客户端是如何发的,如果不知道是哪个发的,那么请在
                  // 两个onMessage方法中打印日志,那么就可以看到哪个可以接收到相应数据
                  @Override
                  public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {
                    System.out.println("onMessage with ByteString:" + new String(bytes.toByteArray()));

                  }

                  @Override
                  public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {
                    super.onOpen(webSocket, response);
                  }
                });

    // 发送文本数据数据
    webSocket.send("hello");
    // 发送二进制数据,同理:二选其一,具体使用哪个发数据,需要知道服务端是如何定义的,
    // 如果不知道 哪个可以发成功,请两个都尝试一下
    webSocket.send(ByteString.of("hello".getBytes(StandardCharsets.UTF_8)));
  }
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐