一、HTTP代理服務(wù)器
HTTP代理服務(wù)器是一個(gè)中間服務(wù)器,它負(fù)責(zé)接收客戶(hù)端的HTTP請(qǐng)求,然后將請(qǐng)求轉(zhuǎn)發(fā)給目標(biāo)服務(wù)器,并將目標(biāo)服務(wù)器返回的響應(yīng)返回給客戶(hù)端。代理服務(wù)器可以處理各種HTTP請(qǐng)求,如GET、POST、PUT、DELETE等,并可以處理HTTPS請(qǐng)求。在開(kāi)發(fā)Web應(yīng)用程序時(shí),使用代理服務(wù)器可以隱藏后端服務(wù)器的真實(shí)IP地址,增強(qiáng)安全性。
二、Java Socket
Java Socket是Java網(wǎng)絡(luò)編程中的重要部分,它提供了一種使用TCP協(xié)議進(jìn)行網(wǎng)絡(luò)通信的方式。使用Java Socket,我們可以創(chuàng)建一個(gè)套接字,連接到遠(yuǎn)程主機(jī),并通過(guò)套接字發(fā)送和接收數(shù)據(jù)。
三、思路
創(chuàng)建SocketServer監(jiān)聽(tīng)端口,根據(jù)http請(qǐng)求頭信息建立代理服務(wù)器與目標(biāo)服務(wù)器的連接,然后通過(guò)httpclient轉(zhuǎn)發(fā)請(qǐng)求數(shù)據(jù),然后將目標(biāo)服務(wù)器的響應(yīng)消息通過(guò)socket連接返回給客戶(hù)端。
四、示例代碼
創(chuàng)建socket監(jiān)聽(tīng)
/**
* @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();
}
}
}
請(qǐng)求轉(zhuǎn)發(fā)處理
@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");
// 解析請(qǐng)求地址 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;
}
// 用戶(hù)鑒權(quán)
Authenticator authenticator = new Authenticator();
authenticator.authenticateByMemory(read.getServiceName(), read.getUserName(), read.getPassword());
// 服務(wù)路由 根據(jù)服務(wù)名獲取實(shí)際的服務(wù)地址和端口,這里處理的是http請(qǐng)求
ServiceRegistration serviceRegistration = new ServiceRegistration();
String target = serviceRegistration.getTarget(read.getServiceName());
// 使用jdk的http客戶(hù)端發(fā)起真實(shí)的請(qǐng)求
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();
}
// 響應(yīng)目標(biāo)服務(wù)器消息
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("服務(wù)器代理異常!");
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
其他輔助類(lèi)
/**
* 用戶(hù)鑒權(quán)判斷
*
* @param serviceName 代理的服務(wù)名稱(chēng)
* @param userName 用戶(hù)名
* @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("服務(wù)不存在");
}
String user = service.get(userName);
if(Objects.isNull(user)){
throw new RuntimeException("用戶(hù)不存在");
}else if(!user.equals(password)){
throw new RuntimeException("密碼錯(cuò)誤");
}
}
/**
* 解析請(qǐng)求頭
*
* @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("錯(cuò)誤的請(qǐng)求");
}else if(!split[0].contains(GET) && !split[0].contains(POST)){
throw new RuntimeException("錯(cuò)誤的請(qǐng)求方式");
}
String[] data = split[0].split(" ");
if(!data[1].contains("?")){
throw new RuntimeException("未攜帶用戶(hù)參數(shù)");
}
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("未攜帶用戶(hù)消息");
}
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;
}
五、測(cè)試效果
通過(guò)postman請(qǐng)求本地服務(wù)代理到遠(yuǎn)程目標(biāo)服務(wù)上。
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-779139.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-779139.html
到了這里,關(guān)于JAVA寫(xiě)HTTP代理服務(wù)器-socket實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!