由于Safari浏览器严格的cookie政策,我无法在exalple1.com域页面上调用exalple2.com接口。现在我想通过转发后端来解决这个问题,即页面上的所有请求都发送到exalple1.com。如果页面要调用的接口是exalple2.com/user/mine,则页面可以是exalple1.com/exalple2-api/user/mine,后端转发到exalple2.com/user/mine,并返回return从 exalple2.com/user/mine 获取到前端的值。请求http://example1.com/example2-api/user/mine时页面携带的所有参数都需要原样传输到http://example2.com/user/mine,例如body 或 url 或请求标头中的参数。您有什么想法通过拦截器来实现这个功能吗?非常感谢您的帮助!
我尝试使用请求接收到的信息重新生成HTTP请求并使用RestTemplate发送它,但响应是乱码。
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class ForwardInterceptor implements HandlerInterceptor {
private RestTemplate restTemplate;
public ForwardInterceptor(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取原始请求的URL、请求方法、请求体和请求头
String originalUrl = request.getRequestURI();
String originalMethod = request.getMethod();
String originalBody = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
HttpHeaders originalHeaders = new HttpHeaders();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
originalHeaders.add(headerName, headerValue);
}
// 构建转发请求的URL
String forwardUrl = "http://example2.com" + originalUrl;
// 创建转发请求
RequestEntity<String> requestEntity = new RequestEntity<>(originalBody, originalHeaders, HttpMethod.valueOf(originalMethod), URI.create(forwardUrl));
// 发送转发请求
ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
// 将转发请求的响应设置到原始响应中
response.setStatus(responseEntity.getStatusCodeValue());
response.setContentType(responseEntity.getHeaders().getContentType().toString());
response.getWriter().write(responseEntity.getBody());
return false; // 停止后续处理
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在请求处理完成后的操作
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 在请求完成后的操作
}
}
因为客户端发送请求时,带上了Accept-Encoding,告诉服务器可以用GZIP压缩返回,但是RestTemplate默认不支持GZIP,所以当返回数据转换成字符串时,甚至字母和数字。
解决方案:
手动去掉Accept-Entiding,直接去掉代码中的请求头
originalHeaders.remove(HttpHeaders.ACCEPT_ENCODING);
配置RestTemplate,支持GZIP
this.restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build()));
添加httpclient依赖
org.apache.httpcomponents http客户端