注:gateway网关当然可以实现这个功能啊啊,不要问我为什么不使用网关,是因为那个项目用不了网关,只能用filter做一个低配版
应用场景:本服务将请求转发到其他服务器,将结果返回
浏览器请求:https://192.168.0.199:7000/demo1/examine/pulse
希望请求转发到 https://192.168.0.199:7004/demo2/examine/pulse
想法:一开始想用请求的转发和重定向实现,但是转发针对的是同一个服务器,重定向又不能携带参数,所以用SpringBoot的RestTemplate发送http请求,得到结果后在网关返回数据给客户端
转发和重定向的特点和区别
1.转发
1、转发是服务器端行为
2、转发整个过程浏览器端只做了一次请求
3、转发浏览器地址不变
4、在转发过程中request域中的数据不会丢失
5、转发只能将请求转发给同一个web应用中的组件
2.重定向
1、重定向是客户端行为
2、重定向是浏览器做了至少两次的访问请求
3、重定向浏览器地址改变
4、重定向两次跳转之间request域中信息数据会丢失(新的request会替代旧request但是不会继承旧request中的数据)
5、重定向可以指向任何资源,包括当前应用程序中的其他资源、同一站点上其他应用程序中的资源以及其他站点的资源
流程:写了一段不怎么好的代码,单独的一个SpringBoot启动,作为网关,请求进来以后进行拦截,是本服务处理的就进入过滤链,要转发到别的服务的就解析获取请求类型、请求头、请求体,然后使用RestTemplate携带这些内容原封不动的发送出去,返回请求的结果result到网关,然后返回客户端。
写的不好,但是我觉得这解析请求中的请求类型、请求头、请求体的方法可以记一下,毕竟下次我就记不起来了hha
import lombok.extern.log4j.Log4j2;
import org.springframework.core.Ordered;
import org.springframework.http.*;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sound.midi.Soundbank;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
@WebFilter
@Component
@Log4j2
public class DemoFilter implements Filter, Ordered {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
System.out.println("================进入过滤器=================");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String requestURI = req.getRequestURI();
if ("/demo1/test".equals(requestURI)) {
// 要处理的请求,本服务
chain.doFilter(request,response);
} else {
// 转发请求,如果是同一个服务器可以直接调用转发请求的方法,这里要做的是转发请求另一个服务的接口,然后返回请求结果
// 1、地址栏有传参数需要进行拼接参数
String queryString = req.getQueryString();//地址栏参数
if (queryString != null) {
// 地址有参数,拼接
requestURI = requestURI + "?" +queryString;
}
// 2、拼接转发的IP和端口
InetAddress ip;
String IP = null;
try {
ip = Inet4Address.getLocalHost();
IP = ip.getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
String url = "http://" + IP + ":7004" + requestURI;
// 3、请求类型
String method = req.getMethod();
HttpMethod httpMethod = HttpMethod.resolve(method);//method
// 4、请求头
MultiValueMap<String, String> headers = parseRequestHeader(req);//header
// 5、请求体
byte[] body = parseRequestBody(req);//body
// 6、封装发singhttp请求
RequestEntity requestEntity = new RequestEntity(body, headers, httpMethod, URI.create(redirectUrl));
RestTemplate restTemplate = new RestTemplate();
//编码格式转换
restTemplate.getMessageConverters().set(1,new StringHttpMessageConverter(StandardCharsets.UTF_8));
ResponseEntity<String> result = restTemplate.exchange(requestEntity, String.class);
// 将转发请求得到的结果和响应头返回客户端
String resultBody = result.getBody();
HttpHeaders resultHeaders = result.getHeaders();
MediaType contentType = resultHeaders.getContentType();
if (contentType != null) {
resp.setContentType(contentType.toString());
}
resp.setCharacterEncoding("UTF-8");// 在getWriterz之前执行,否则不生效
PrintWriter writer = resp.getWriter();
writer.write(resultBody);
writer.flush();
}
}
@Override
public void destroy() {
System.out.println("================destroy()=================");
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
/**
* request body
* @param request
* @return
* @throws IOException
*/
private byte[] parseRequestBody(HttpServletRequest request) throws IOException {
InputStream inputStream = request.getInputStream();
return StreamUtils.copyToByteArray(inputStream);
}
/**
* request header
* @param request
* @return
*/
private MultiValueMap<String, String> parseRequestHeader(HttpServletRequest request) {
HttpHeaders httpHeaders = 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) {
httpHeaders.add(headerName, headerValue);
}
}
return httpHeaders;
}
}