基于websocket实现将公网请求映射到本地的请求转发(客户端篇)

公网ip可以被互联网访问,而本机的私有ip则不被允许,如何实现将公网ip的请求映射到本机的室友ip呢,我们基于websocket技术,将访问服务器的请求全部转发到本机上

websocket实现的话,是需要分为两个端,第一个是放在公网的服务端,第二个是放在本机的客户端,客户端则需要主动的去请求公网的服务端,实现连接成功后,服务端会把所有的请求推给客户端,客户端处理完成后,则将处理结果返回给服务端,再由服务端返回给请求端

客户端篇

     <!-- okhttp        -->
        <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.10.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.java-websocket/Java-WebSocket -->
        <dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.5.0</version>
        </dependency>

okhttp请求工具类,实现将客户端获取到的请求转发出去

package com.example.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import okhttp3.*;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @author Xiongx
 * @version 1.0
 * @date 2021/7/2 10:35
 * @since JDK 1.8
 */
public class OkHttpUtils {


    private static volatile OkHttpClient okHttpClient = null;
    private static volatile Semaphore semaphore = null;
    private Map<String, String> headerMap;
    private Map<String, String> paramMap;
    private String url;
    private Request.Builder request;

    /**
     * 初始化okHttpClient,并且允许https访问
     */
    private OkHttpUtils() {
        if (okHttpClient == null) {
            synchronized (OkHttpUtils.class) {
                if (okHttpClient == null) {
                    TrustManager[] trustManagers = buildTrustManagers();
                    okHttpClient = new OkHttpClient.Builder()
                            .connectTimeout(150, TimeUnit.MINUTES)
                            .writeTimeout(200000, TimeUnit.SECONDS)
                            .readTimeout(200000, TimeUnit.SECONDS)
                            .sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager) trustManagers[0])
                            .hostnameVerifier((hostName, session) -> true)
                            .retryOnConnectionFailure(true)
                            .build();
                    addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
                }
            }
        }
    }

    /**
     * 用于异步请求时,控制访问线程数,返回结果
     *
     * @return
     */
    private static Semaphore getSemaphoreInstance() {
        //只能1个线程同时访问
        synchronized (OkHttpUtils.class) {
            if (semaphore == null) {
                semaphore = new Semaphore(0);
            }
        }
        return semaphore;
    }

    /**
     * 创建OkHttpUtils
     *
     * @return
     */
    public static OkHttpUtils builder() {
        return new OkHttpUtils();
    }

    /**
     * 添加url
     *
     * @param url
     * @return
     */
    public OkHttpUtils url(String url) {
        this.url = url;
        return this;
    }

    /**
     * 添加参数
     *
     * @param key   参数名
     * @param value 参数值
     * @return
     */
    public OkHttpUtils addParam(String key, String value) {
        if (paramMap == null) {
            paramMap = new LinkedHashMap<>(16);
        }
        paramMap.put(key, value);
        return this;
    }


    public OkHttpUtils addParamMap(Map<String, Object> map){
        if(paramMap==null){
            paramMap= new LinkedHashMap<>(16);
        }
        map.forEach((k,v)->{
            String value= JSONObject.toJSONString(v, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
            paramMap.put(k,value);
        });
        return this;
    }

    public OkHttpUtils addJson(JSONObject json){
        if(paramMap==null){
            paramMap= new LinkedHashMap<>(16);
        }
        json.forEach((k, v) -> {
            String value= JSONObject.toJSONString(v, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
            paramMap.put(k,value);
        });
        return this;
    }



    /**
     * 添加请求头
     *
     * @param key   参数名
     * @param value 参数值
     * @return
     */
    public OkHttpUtils addHeader(String key, String value) {
        if (headerMap == null) {
            headerMap = new LinkedHashMap<>(16);
        }
        headerMap.put(key, value);
        return this;
    }

    public OkHttpUtils addHeader(Map<String,String> heards){
        if (headerMap == null) {
            headerMap = new LinkedHashMap<>(16);
        }
        if(heards!=null){
            for (Map.Entry<String, String> entry : heards.entrySet()) {
                headerMap.put(entry.getKey(), entry.getValue());
            }
        }
        return this;
    }

    /**
     * 初始化get方法
     *
     * @return
     */
    public OkHttpUtils get() {
        request = new Request.Builder().get();
        StringBuilder urlBuilder = new StringBuilder(url);
        if (paramMap != null) {
            urlBuilder.append("?");
            try {
                for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                    urlBuilder.append(URLEncoder.encode(entry.getKey(), "utf-8")).
                            append("=").
                            append(URLEncoder.encode(entry.getValue(), "utf-8")).
                            append("&");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            urlBuilder.deleteCharAt(urlBuilder.length() - 1);
        }
        request.url(urlBuilder.toString());
        return this;
    }

    /**
     * 初始化post方法
     *
     * @param isJsonPost true等于json的方式提交数据,类似postman里post方法的raw
     *                   false等于普通的表单提交
     * @return
     */
    public OkHttpUtils post(boolean isJsonPost) {
        RequestBody requestBody;
        if (isJsonPost) {
            String json = "";
            if (paramMap != null) {
                json = JSON.toJSONString(paramMap);
            }
            requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        } else {
            FormBody.Builder formBody = new FormBody.Builder();
            if (paramMap != null) {
                paramMap.forEach(formBody::add);
            }
            requestBody = formBody.build();
        }
        request = new Request.Builder().post(requestBody).url(url);
        return this;
    }


    public OkHttpUtils post(Map<String, Object> objectMap) {
        RequestBody requestBody;

        String json = "";
        if (objectMap != null) {
            json = JSON.toJSONString(objectMap);
        }
        requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);

        request = new Request.Builder().post(requestBody).url(url);
        return this;
    }

    /**
     * 同步请求
     *
     * @return
     */
    public String sync() {
        setHeader(request);
        try {
            Response response = okHttpClient.newCall(request.build()).execute();
            assert response.body() != null;
            return response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
            return "请求失败:" + e.getMessage();
        }
    }

    /**
     * 异步请求,有返回值
     */
    public String async() {
        StringBuilder buffer = new StringBuilder("");
        setHeader(request);
        okHttpClient.newCall(request.build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                buffer.append("请求出错:").append(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                assert response.body() != null;
                buffer.append(response.body().string());
                getSemaphoreInstance().release();
            }
        });
        try {
            getSemaphoreInstance().acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return buffer.toString();
    }

    /**
     * 异步请求,带有接口回调
     *
     * @param callBack
     */
    public void async(ICallBack callBack) {
        setHeader(request);
        okHttpClient.newCall(request.build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callBack.onFailure(call, e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                assert response.body() != null;
                callBack.onSuccessful(call, response.body().string());
            }
        });
    }

    /**
     * 为request添加请求头
     *
     * @param request
     */
    private void setHeader(Request.Builder request) {
        if (headerMap != null) {
            try {
                for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                    request.addHeader(entry.getKey(), entry.getValue());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 生成安全套接字工厂,用于https请求的证书跳过
     *
     * @return
     */
    private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ssfFactory;
    }

    private static TrustManager[] buildTrustManagers() {
        return new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[]{};
                    }
                }
        };
    }

    /**
     * 自定义一个接口回调
     */
    public interface ICallBack {

        void onSuccessful(Call call, String data);

        void onFailure(Call call, String errorMsg);

    }

    public void Demo(){
        OkHttpUtils.builder().url("请求地址,http/https都可以")
                // 有参数的话添加参数,可多个
                .addParam("参数名", "参数值")
                .addParam("参数名", "参数值")
                // 也可以添加多个
                .addHeader("Content-Type", "application/json; charset=utf-8")
                .get()
                // 可选择是同步请求还是异步请求
                //.async();
                .sync();

        // post请求,分为两种,一种是普通表单提交,一种是json提交
       OkHttpUtils.builder().url("请求地址,http/https都可以")
                // 有参数的话添加参数,可多个
                .addParam("参数名", "参数值")
                .addParam("参数名", "参数值")
                // 也可以添加多个
                .addHeader("Content-Type", "application/json; charset=utf-8")
                // 如果是true的话,会类似于postman中post提交方式的raw,用json的方式提交,不是表单
                // 如果是false的话传统的表单提交
                .post(true)
                .sync();

        // 选择异步有两个方法,一个是带回调接口,一个是直接返回结果
       OkHttpUtils.builder().url("")
                .post(false)
                .async();

        OkHttpUtils.builder().url("").post(false).async(new ICallBack() {
            @Override
            public void onSuccessful(Call call, String data) {
                // 请求成功后的处理
            }

            @Override
            public void onFailure(Call call, String errorMsg) {
                // 请求失败后的处理
            }
        });

    }
}

websocketconfig工具类
import com.alibaba.fastjson.JSONObject;
import com.example.utils.FileUtils;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.stereotype.Component;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.time.LocalDate;

/**
 * @Classname WebSockerConfig
 * @Description TODO
 * @Date 2023/3/8 20:34
 * @Created by XiongXiong
 * @Author: X.I.O
 */
@Component
public class WebSockerConfig {

    private static String urlAddr="ws://ip:8090/wsconnection";

	//服务网关
    private static String getWayUrl="http://127.0.0.1:8004";

    private static WebSocketClient mWs;


    public void sendMessage() throws URISyntaxException {
        if(mWs==null){
            URI uri = new URI(urlAddr);
            mWs= new WebSocketClient(uri) {
                @Override
                public void onOpen(ServerHandshake serverHandshake) {

                }

                @Override
                public void onMessage(ByteBuffer bytes) {
                    super.onMessage(bytes);
                }

                @Override
                public void send(byte[] data) {
                    super.send(data);
                }

                @Override
                public void onMessage(String s) {
                    System.out.println("收到消息"+s);
                    System.out.println(s+" 收到服务器的消息了");
                    if("file".equals(s)){
                        byte[] file= FileUtils.getByteByFile(new File("D:\\Users\\X.I.O\\Pictures\\微信图片_20230115133944.jpg"));
                        ByteBuffer buffer=FileUtils.byte2Byffer(file);
                        System.out.println("开始发送文件数据"+file.length);
                        this.send(buffer);
                    }else {
                        JSONObject obj=JSONObject.parseObject(s);
                        if(obj.containsKey("code") && "200".equals(obj.getString("code"))){
                            RequestModel requestModel=JSONObject.parseObject(s,RequestModel.class);
                            String url=requestModel.getUrl();
                            url=getWayUrl+url;
                            if("GET".equals(requestModel.getMethod())){
                                String queryString=requestModel.getQueryString();
                                if(!"".equals(queryString) && queryString!=null){
                                    url=url+"?"+queryString;
                                }
                                System.out.println("请求地址:"+url);
                                OkHttpUtils okHttpUtils=OkHttpUtils.builder();
                                okHttpUtils.url(url);
                                if(requestModel.getQueryMap()!=null){
                                    okHttpUtils.addParamMap(requestModel.getQueryMap());
                                }
                                okHttpUtils.addHeader(requestModel.getHearders());
                                String str=okHttpUtils.get().sync();
                                System.out.println(str+" 执行结果");
                                this.send(str);
                            }
                            if("POST".equals(requestModel.getMethod())){
                                String queryString=requestModel.getQueryString();
                                if(!"".equals(queryString) && queryString!=null){
                                    url=url+"?"+queryString;
                                }
                                System.out.println("请求地址:"+url);
                                OkHttpUtils okHttpUtils=OkHttpUtils.builder();
                                okHttpUtils.url(url);
                                okHttpUtils.addHeader(requestModel.getHearders());
                                JSONObject json=requestModel.getBody();
                                if(json != null && !json.isEmpty()){
                                    okHttpUtils.addJson(requestModel.getBody());
                                    okHttpUtils.post(true);
                                    String rsult=okHttpUtils.sync();
                                    this.send(rsult);
                                }else {

                                    if(requestModel.getQueryMap()!=null){
                                        okHttpUtils.addParamMap(requestModel.getQueryMap());
                                    }
                                    okHttpUtils.post(false);
                                    String result=okHttpUtils.sync();
                                    this.send(result);
                                }
                            }
                        }
                    }
                }

                @Override
                public void onClose(int i, String s, boolean b) {

                    System.out.println(s+" 我关闭了");
                }

                @Override
                public void onError(Exception e) {

                    System.out.println(e.getMessage()+" 为啥阿");
                }
            };
            mWs.connect();
        }
        while (!mWs.isOpen()){
            //先阻塞会
        }
        if(mWs.isOpen()){
            JSONObject obj=new JSONObject();
            obj.put("code",0);
            obj.put("msg","开始连接");
            mWs.send(obj.toJSONString());
        }
    }
}

FileUtils

/**
 * @Classname FileUtils
 * @Description TODO
 * @Date 2023/3/8 13:51
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class FileUtils {

    /**
     * byte 数组转byteBuffer
     * @param byteArray
     */
    public static ByteBuffer byte2Byffer(byte[] byteArray) {
        //初始化一个和byte长度一样的buffer
        ByteBuffer buffer=ByteBuffer.allocate(byteArray.length);
        // 数组放到buffer中
        buffer.put(byteArray);
        //重置 limit 和postion 值 否则 buffer 读取数据不对
        buffer.flip();
        return buffer;
    }


    public static byte[] bytebuffer2ByteArray(ByteBuffer buffer) {
        //重置 limit 和postion 值
        buffer.flip();
        //获取buffer中有效大小
        int len=buffer.limit() - buffer.position();

        byte [] bytes=new byte[len];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i]=buffer.get();
        }
        return bytes;
    }

    public static byte[] getByteByFile(File file){
        FileInputStream fis=null;
        try {
            byte[] bytesArray = new byte[(int) file.length()];
            fis = new FileInputStream(file);
            fis.read(bytesArray);
            return bytesArray;
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fis != null) {
                try {
                    fis.close();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static void byteToFile(byte[] bytes,File file){
        OutputStream out = null;
        InputStream is = null;
        try {
            out = new FileOutputStream(file);
            is = new ByteArrayInputStream(bytes);
            byte[] buff = new byte[1024];
            int len = 0;
            while((len=is.read(buff))!=-1){
                out.write(buff, 0, len);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (is != null) {
                try {
                    is.close();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out != null){
                try {
                    out.close();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

初始化配置

@Component
public class InitConfig {

    @Autowired
    private WebSockerConfig webSockerConfig;

    @PostConstruct
    public void init() throws URISyntaxException {
        webSockerConfig.sendMessage();
    }
}

RequestModel


import com.alibaba.fastjson.JSONObject;

import java.io.Serializable;
import java.util.Map;

/**
 * @Classname RequestModel
 * @Description TODO
 * @Date 2023/3/8 20:06
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class RequestModel implements Serializable {

    private Integer code;

    private String url;

    private Map<String,String> hearders;

    private String method;

    private Map<String,Object> queryMap;

    private JSONObject body;

    private String queryString;

    private String scheme;

    private String remoteAddress;

    private String remoteHost;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getRemoteHost() {
        return remoteHost;
    }

    public void setRemoteHost(String remoteHost) {
        this.remoteHost = remoteHost;
    }

    public String getQueryString() {
        return queryString;
    }

    public void setQueryString(String queryString) {
        this.queryString = queryString;
    }

    public String getScheme() {
        return scheme;
    }

    public void setScheme(String scheme) {
        this.scheme = scheme;
    }

    public String getRemoteAddress() {
        return remoteAddress;
    }

    public void setRemoteAddress(String remoteAddress) {
        this.remoteAddress = remoteAddress;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Map<String, String> getHearders() {
        return hearders;
    }

    public void setHearders(Map<String, String> hearders) {
        this.hearders = hearders;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public Map<String, Object> getQueryMap() {
        return queryMap;
    }

    public void setQueryMap(Map<String, Object> queryMap) {
        this.queryMap = queryMap;
    }

    public JSONObject getBody() {
        return body;
    }

    public void setBody(JSONObject body) {
        this.body = body;
    }

    public RequestModel(String url, Map<String, String> hearders, String method, Map<String, Object> queryMap, JSONObject body) {
        this.url = url;
        this.hearders = hearders;
        this.method = method;
        this.queryMap = queryMap;
        this.body = body;
    }

    public RequestModel() {
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值