JAVA写HTTP代理服务器-socket实现

一、HTTP代理服务器

HTTP代理服务器是一个中间服务器,它负责接收客户端的HTTP请求,然后将请求转发给目标服务器,并将目标服务器返回的响应返回给客户端。代理服务器可以处理各种HTTP请求,如GET、POST、PUT、DELETE等,并可以处理HTTPS请求。在开发Web应用程序时,使用代理服务器可以隐藏后端服务器的真实IP地址,增强安全性。

二、Java Socket

Java Socket是Java网络编程中的重要部分,它提供了一种使用TCP协议进行网络通信的方式。使用Java Socket,我们可以创建一个套接字,连接到远程主机,并通过套接字发送和接收数据。

三、思路

创建SocketServer监听端口,根据http请求头信息建立代理服务器与目标服务器的连接,然后通过httpclient转发请求数据,然后将目标服务器的响应消息通过socket连接返回给客户端。

四、示例代码

创建socket监听

/**
 * @author Charles
 * @module socket
 * @since 2023/8/3 12:03
 */
public class InitProxyServer {

    public void startServer(int port) {
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            while (true) {
                //The server socket
                Socket socket = serverSocket.accept();
                new ProxyServer(socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

请求转发处理

@Override
public void run() {
    try {
        StringBuffer res = new StringBuffer();
        String content = "";
        res.append("HTTP/1.1 200 ok \r\n");
        res.append("Content-Type:application/json;charset=utf-8; \r\n");
        // 解析请求地址  http(s)://serviceName/路径?userName=xxx&passWord=xxx&other=xxx
        RequestData read = Request.read(this.input);
        if(read == null){
            res.append("Content-Length:" + content.getBytes().length + "\r\n");
            res.append("\r\n");
            res.append(content);
            out.write(res.toString().getBytes());
            out.flush();
            return;
        }
        // 用户鉴权
        Authenticator authenticator = new Authenticator();
        authenticator.authenticateByMemory(read.getServiceName(), read.getUserName(), read.getPassword());
        // 服务路由 根据服务名获取实际的服务地址和端口,这里处理的是http请求
        ServiceRegistration serviceRegistration = new ServiceRegistration();
        String target = serviceRegistration.getTarget(read.getServiceName());
        // 使用jdk的http客户端发起真实的请求
        String body = "";
        if(read.getMethodType().contains(GET)){
            body = HttpUtil.createGet(target + read.getRequestPath()).body(read.getParamBody()).execute().body();
        }
        if(read.getMethodType().contains(POST)){
            body = HttpUtil.createPost(target + read.getRequestPath()).body(read.getParamBody()).execute().body();
        }
        // 响应目标服务器消息
        content = body;
        res.append("Content-Length:" + content.getBytes().length + "\r\n");
        res.append("\r\n");
        res.append(content);
        out.write(res.toString().getBytes());
        out.flush();
    }catch (Exception e){
        System.out.println("服务器代理异常!");
        e.printStackTrace();
    }finally {
        try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

其他辅助类

/**
 * 用户鉴权判断
 *
 * @param serviceName 代理的服务名称
 * @param userName 用户名
 * @param password 密码
 */
public void authenticateByMemory(String serviceName, String userName, String password){
    Map<String, String> service = memoryUser.get(serviceName);
    if(Objects.isNull(service)){
        throw new RuntimeException("服务不存在");
    }
    String user = service.get(userName);
    if(Objects.isNull(user)){
        throw new RuntimeException("用户不存在");
    }else if(!user.equals(password)){
        throw new RuntimeException("密码错误");
    }
}

/**
 * 解析请求头
 *
 * @param input
 * @return
 */
public static RequestData read(InputStream input) {
    StringBuilder stringBuilder = new StringBuilder();
    try {
        byte[] bytes = new byte[1024];
        while (input.available() != 0) {
            input.read(bytes);
            String str = new String(bytes, Charset.forName("utf-8"));
            stringBuilder.append(str);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    String accept = stringBuilder.toString();
    if("".equals(accept)){
        return null;
    }
    String[] split = accept.split("\\r\\n");
    if(!split[0].contains(HTTP)){
        throw new RuntimeException("错误的请求");
    }else if(!split[0].contains(GET) && !split[0].contains(POST)){
        throw new RuntimeException("错误的请求方式");
    }
    String[] data = split[0].split(" ");
    if(!data[1].contains("?")){
        throw new RuntimeException("未携带用户参数");
    }
    RequestData requestData = new RequestData();
    requestData.setMethodType(data[0].replace("/", ""));
    requestData.setRequestPath(data[1].substring(data[1].indexOf("/", 1), data[1].indexOf("?")));
    requestData.setServiceName(data[1].substring(1, data[1].indexOf("/", 1)));
    String auth = data[1].substring(data[1].indexOf("?") + 1);
    requestData.setParamBody(auth);
    if(Objects.isNull(auth) || !auth.contains(USERNAME) || !auth.contains(PASSWORD)){
        throw new RuntimeException("未携带用户消息");
    }
    String[] keyValue = auth.split("&");
    for (int i = 0; i < keyValue.length; i++) {
        if(keyValue[i].contains(USERNAME)){
            requestData.setUserName(keyValue[i].replace(USERNAME, "").replace("=", ""));
        }
        if(keyValue[i].contains(PASSWORD)){
            requestData.setPassword(keyValue[i].replace(PASSWORD, "").replace("=", ""));
        }
    }
    return requestData;
}

五、测试效果

通过postman请求本地服务代理到远程目标服务上。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要现一个代理服务器,你可以使用Java中的Socket和ServerSocket类。以下是一个简单的例子来演示如何实现一个基本的代理服务器: ```java import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class ProxyServer { public static void main(String[] args) { try { // 创建ServerSocket监听指定端口 ServerSocket serverSocket = new ServerSocket(8080); while (true) { // 接受客户端连接 Socket clientSocket = serverSocket.accept(); // 创建新线程处理客户端请求 new ProxyThread(clientSocket).start(); } } catch (IOException e) { e.printStackTrace(); } } static class ProxyThread extends Thread { private Socket clientSocket; public ProxyThread(Socket clientSocket) { this.clientSocket = clientSocket; } @Override public void run() { try { // 从客户端获取输入流和输出流 InputStream clientInput = clientSocket.getInputStream(); OutputStream clientOutput = clientSocket.getOutputStream(); // 创建与目标服务器的连接 Socket serverSocket = new Socket("目标服务器IP", 80); InputStream serverInput = serverSocket.getInputStream(); OutputStream serverOutput = serverSocket.getOutputStream(); // 将客户端请求发送给目标服务器 byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = clientInput.read(buffer)) != -1) { serverOutput.write(buffer, 0, bytesRead); serverOutput.flush(); } // 将目标服务器的响应发送给客户端 while ((bytesRead = serverInput.read(buffer)) != -1) { clientOutput.write(buffer, 0, bytesRead); clientOutput.flush(); } // 关闭连接 clientSocket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } ``` 需要将代码中的"目标服务器IP"替换为你想要代理的服务器IP地址。此代码片段创建一个代理服务器监听端口8080,并将客户端的请求转发到目标服务器
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值