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

有人会杠:这个功能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 对应配置的功能

go语言实现

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

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 headers = new HashMap();

// 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(),

new ArrayList(),

null,

headers,

new HashMap(),

new HashMap(),

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)));

}

}

参考阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: