Http反向代理

前言

背景: 有些时候需要对一些接口进行透传, 由于没有任何逻辑, 我们无需直到请求响应对象到底是什么样的, 原样输入输出即可

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package com.example.corsdemo;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.TextNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;

/**
* @author cuishiying
* @date 2022-04-21
*/
@Slf4j
@Service
public class RoutingDelegate {

public ResponseEntity<JsonNode> redirect(HttpServletRequest request, HttpServletResponse response, String routeUrl,
String prefix) {
try {
String redirectUrl = createRedictUrl(request, routeUrl, prefix);
RequestEntity<byte[]> requestEntity = createRequestEntity(request, redirectUrl);
return route(requestEntity);
}
catch (Exception e) {
log.error("RoutingDelegate请求错误, request: {}, err: {}", request, e);
return new ResponseEntity<>(new TextNode("RoutingDelegate err"), HttpStatus.INTERNAL_SERVER_ERROR);
}
}

/**
* @param request 原始请求:
* http://localhost:7110/eachbot-knowledge-proxy-web/delegate/get/1?name=admin
* @param routeUrl 代理请求: http://localhost:8088
* @param prefix 原请求需要截取掉的路径
* @return 代理完整URL
*/
private String createRedictUrl(HttpServletRequest request, String routeUrl, String prefix) {
String queryString = request.getQueryString();
return routeUrl + request.getRequestURI().replace(prefix, "") + (queryString != null ? "?" + queryString : "");
}

/**
* 代理
*/
private ResponseEntity<JsonNode> route(RequestEntity<byte[]> requestEntity) {
RestTemplate restTemplate = new RestTemplate();
return restTemplate.exchange(requestEntity, JsonNode.class);
}

/**
* 构建请求体
*/
private RequestEntity<byte[]> createRequestEntity(HttpServletRequest request, String url)
throws URISyntaxException, IOException {
String method = request.getMethod();
HttpMethod httpMethod = HttpMethod.resolve(method);
MultiValueMap<String, String> headers = parseRequestHeader(request);
byte[] body = parseRequestBody(request);
return new RequestEntity<>(body, headers, httpMethod, new URI(url));
}

/**
* 构建请求体
*/
private byte[] parseRequestBody(HttpServletRequest request) throws IOException {
InputStream inputStream = request.getInputStream();
return StreamUtils.copyToByteArray(inputStream);
}

/**
* 构建请求头
*/
private MultiValueMap<String, String> parseRequestHeader(HttpServletRequest request) {
HttpHeaders headers = new HttpHeaders();
List<String> headerNames = Collections.list(request.getHeaderNames());
for (String headerName : headerNames) {
List<String> headerValues = Collections.list(request.getHeaders(headerName));
for (String headerValue : headerValues) {
headers.add(headerName, headerValue);
}
}
return headers;
}

}

web

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RestController
@RequestMapping("/delegate")
public class DelegateController {

@Resource
private RoutingDelegate routingDelegate;

/**
* // @formatter:off
* 目标应用URI: /app/user/7
* 前端完整地址: https://xx.xx.xx.xx/context/delegate/app/user/7
* 代理目标地址: http://127.0.0.1/app/user/7
* // @formatter:on
*/
@RequestMapping(value = "/**", method = { RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT,
RequestMethod.DELETE, RequestMethod.PATCH })
public Object delegate(HttpServletRequest request, HttpServletResponse response) {
ResponseEntity<JsonNode> responseEntity = routingDelegate.redirect(request, response, "http://127.0.0.1",
"/context/delegate");
return responseEntity.getBody();
}

}

最后

本文到此结束,感谢阅读。如果您觉得不错,请关注公众号【当我遇上你】,您的支持是我写作的最大动力。