SpringBoot用Filter实现轻量级网关,实现拦截请求和转发请求

: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;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值