• ReqAndRespAndZuul的一些自己的见解,和超时异常的解方案


    1、先说说请求和响应对象再过滤器里转发和重定向的总结

    总结:

    1. 如果过滤器里发生了重定向或者转发,那么,原客户端收到的响应一定是最后重定向或者转发后的响应,前面都不算

    2. 但是如果原过滤器,放行了原请求,则原请求会走完原来的流程,

    3. 转发,是先走转发的请求方法,转发不走过滤器,而是直接走方法,然后回到原来的方法,因为转发是拿 当前请求和响应对象过去的,所以响应对象被改变了,回到原来的方法之后,继续走完原请求的过滤器链

    4. 重定向是先走完原 最后走重定向的方法 如果一号过滤器发生了重定向,依旧执行后面的过滤器链,执行完原请求所有的过滤器链,才开始走重定向的过滤器链以及重定向的方法。

    5. 但最后响应的结果一定是转发后或者重定向后的响应的数据!

       //重定向的话,就是等原请求的过滤器链走完,响应对象回到客户端,再发请求,再在走新的请求的过滤器链。
    //转发,根本就不会重新走过滤器,而是直接走它的方法 但是会走拦截器
    //不管是重定向还是转发,都不会阻断后续方法的执行,都会执行,
       //不管是重定向还是转发,都可以把响应头带上,重定向是发送两次请求,响应头只会给原请求加,而重定向以后的响应头则没有;而转发是因为同一个请求和响应对象,所以请求头和响应头,都能再转发以后拿到!!!
    
    • 1
    • 2
    • 3
    • 4

    2、Feign调用微服务的转发和响应是什么样?

    证明: 再用Feign进行微服务调用的时候不会进行转发重定向。主要目的是为了拿到数据。JSON。 而不是为了请求转发和重定向!
    还剩三个问题

    1. 网关转发 之后重定向,就是 谁请求,谁就重定向,再转发也就是转发。就当网关就是客户端,发送请求一样。本质是转发,但是是特殊的转发。地址栏不变!
      2. 字符串,到底是JSON还是Text/HTML 给了必要的响应头就是Json,否则永远都是text/html
      3. 网关走不走过滤器呢?通过网关转发的请求会走,转发的请求的过滤器

    3.小实验

    实验2:
        1.   request.getServletContext().getRequestDispatcher("/test").forward(request,response); 这个必须是根目录下开始写
        2.  request.getRequestDispatcher("test")  这个是可以写相对路径,也就是这一级目录下的可以写,就是可以不加斜杠
    
    • 1
    • 2
    • 3

    4.一次转发以后 第一次的请求,和第二次请求的**request.getRequestURI()**会变吗?

    会变的,第一次请求和第二次请求,虽然是同一个请求,但是因为转发是在服务器内部转发,客户端是不知道,所以路径不变,但是服务器知道,所以请求的路径会变!

    5.网关访问微服务超时了怎么办

    zuul:
      host:
        connect-timeout-millis: 5000  # 连接超时时间,单位为毫秒
        socket-timeout-millis: 10000  # 响应超时时间,单位为毫秒
    
    ribbon:
      ConnectTimeout: 5000  #zuul集成了ribbon,底层有ribbon来实现负载均衡
      ReadTimeout: 5000
      SocketTimeout: 5000  #socketTimeout 这个是一个容易被忽略的原因 这些默认是一秒超时
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6.后端解决跨域问题,添加不了响应头怎么办?

    @CrossOrigin(origins = "*",allowedHeaders = "*",exposedHeaders = {"Key"})
    
    • 1

    添加暴露响应头的key就可以把对应的响应头暴露出去

    7.AOP和注解实现 角色权限添加

    1.自定义两个注解
    package com.qf.lawer.annotationConfig;
    
    import com.qf.lawer.enumConst.Logic;
    
    import java.lang.annotation.*;
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME) // 指定注解保留到运行时
    @Target(ElementType.METHOD) // 指定注解可以应用在方法上
    public @interface AddPermitForMethod {
    
        String[] value();
    
        Logic logical() default Logic.AND;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    package com.qf.lawer.annotationConfig;
    
    import com.qf.lawer.enumConst.Logic;
    
    import java.lang.annotation.*;
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME) // 指定注解保留到运行时
    @Target(ElementType.METHOD) // 指定注解可以应用在方法上
    public @interface AddRoleForMethod {
    
        String[] value();
    
        Logic logical() default Logic.AND;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    2.自定义枚举类
    package com.qf.lawer.enumConst;
    
    public enum Logic {
        AND, OR
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    3.自定义切面
    PermitForAspect
    package com.qf.lawer.aop;
    
    import com.qf.lawer.annotationConfig.AddPermitForMethod;
    import com.qf.lawer.annotationConfig.AddRoleForMethod;
    import com.qf.lawer.enumConst.Logic;
    import com.qf.lawer.exceptionConfig.RolesAuthException;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import java.lang.reflect.Method;
    import java.util.Arrays;
    import java.util.List;
    
    @Aspect
    @Component
    public class PermitForAspect {
    
        @Around("@annotation(com.qf.lawer.annotationConfig.AddPermitForMethod)")
        public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
            ServletRequestAttributes request = getRequestAttributes();
            String token = request.getRequest().getHeader("token");
            System.out.println(token);
    
            //解析token拿到权限
    
    
    
    //        System.out.println("Before method");
            AddPermitForMethod annotation = getAnnotation(joinPoint);
            // 访问注解的内容
            if (annotation != null) {
                String[] value = annotation.value();
                Logic logical = annotation.logical();
                switch (logical){
                    case AND:
                        List<String> listAnd = Arrays.asList(value);
                        List<String> userRoles = Arrays.asList(permits());//角色权限
                        boolean b = userRoles.containsAll(listAnd);
                        if (!b){
                            throw new RolesAuthException("权限不够,不允许访问该方法");
                        }
                        System.out.println("权限符合");
                        break;
                    case OR:
                        List<String> listOr = Arrays.asList(value);
                        List<String> userRoles2 = Arrays.asList(permits());//角色权限
                        for (String s : listOr) {
                            userRoles2.contains(s);
                            System.out.println("权限符合");
                            break;
                        }
                            throw new RolesAuthException("权限不够,不允许访问该方法");
                }
    
            }
            Object result = joinPoint.proceed();
    //        System.out.println("after AOP");
    
            return result;
    
        }
    
    
        public String[] permits(){
            return new String[]{"insert","delete"};
        }
    
        private AddPermitForMethod getAnnotation(ProceedingJoinPoint joinPoint) {
            // 获取目标方法
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method method = methodSignature.getMethod();
    
            // 获取注解
            return method.getAnnotation(AddPermitForMethod.class);
        }
    
        public  ServletRequestAttributes getRequestAttributes() {
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            return (ServletRequestAttributes) attributes;
        }
    
    }
    
    
    • 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
    RolesAspect
    package com.qf.lawer.aop;
    
    import com.qf.lawer.annotationConfig.AddRoleForMethod;
    import com.qf.lawer.enumConst.Logic;
    import com.qf.lawer.exceptionConfig.RolesAuthException;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import java.lang.reflect.Method;
    import java.util.Arrays;
    import java.util.List;
    
    @Aspect
    @Component
    public class RolesAspect {
    
        @Around("@annotation(com.qf.lawer.annotationConfig.AddRoleForMethod)")
        public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
            ServletRequestAttributes request = getRequestAttributes();
            String token = request.getRequest().getHeader("token");
            System.out.println(token);
    
            //解析token获取角色
    
    
    //        System.out.println("Before method");
            AddRoleForMethod annotation = getAnnotation(joinPoint);
            // 访问注解的内容
            if (annotation != null) {
                String[] value = annotation.value();
                Logic logical = annotation.logical();
                switch (logical){
                    case AND:
                        List<String> listAnd = Arrays.asList(value);
                        List<String> userRoles = Arrays.asList(roles());//角色权限
                        boolean b = userRoles.containsAll(listAnd);
                        if (!b){
                            throw new RolesAuthException("角色不符合,不允许访问该方法");
                        }
                        System.out.println("角色符合");
                        break;
                    case OR:
                        List<String> listOr = Arrays.asList(value);
                        List<String> userRoles2 = Arrays.asList(roles());//角色权限
                        for (String s : listOr) {
                            userRoles2.contains(s);
                            System.out.println("角色符合");
                            break;
                        }
                            throw new RolesAuthException("角色不符合,不允许访问该方法");
                }
    
            }
            Object result = joinPoint.proceed();
    //        System.out.println("after AOP");
    
            return result;
    
        }
    
    
        public String[] roles(){
            return new String[]{"guest","admin"};
        }
    
        private AddRoleForMethod getAnnotation(ProceedingJoinPoint joinPoint) {
            // 获取目标方法
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method method = methodSignature.getMethod();
    
            // 获取注解
            return method.getAnnotation(AddRoleForMethod.class);
        }
    
        public  ServletRequestAttributes getRequestAttributes() {
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            return (ServletRequestAttributes) attributes;
        }
    
    }
    
    
    • 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

    8.网关向前端返回数据,但是无法使用 全局异常处理器

    1.是因为 网关的还没走到 微服务的dispatcherservlet 网关这边的全局异常处理器捕获不到微服务的 异常。

    2.如果发生了异常,就用响应对象发送一条数据就可以了

    例:token网关过滤器

    package com.qf.lawer.filter;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import com.netflix.zuul.exception.ZuulException;
    import com.qf.lawer.utils.Const;
    import com.qf.lawer.utils.JWTUtils;
    import com.qf.lawer.utils.ZuulResultVoUtils;
    import com.qf.lawer.vo.ResultVo;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Enumeration;
    
    @Component
    @Slf4j
    public class TokenFilter extends ZuulFilter {
    
    
        @Override
        public String filterType() {
            return FilterConstants.PRE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return Integer.MIN_VALUE;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() throws ZuulException {
            RequestContext currentContext = RequestContext.getCurrentContext();
            HttpServletRequest request = currentContext.getRequest();
            //是 路径名  /lawer-firm/firm/list
            String requestURI = request.getRequestURI();
            System.out.println(requestURI);
            if (requestURI.contains("lawer-login")){
                //代表用户登录注册的请求,可以放行
                return null;
            }
            String token = request.getHeader("Token");
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                System.out.println(headerNames.nextElement());
            }
            if (token==null){
                //让请求不要在发送给后续的微服务了 token为空
                currentContext.setSendZuulResponse(false);
                ZuulResultVoUtils.sendErrorResultVo(Const.ERRORCODE,"Token为空,请登录以后再来");
            }else {
                //验证Token
                try {
                    boolean b = JWTUtils.validateToken(token);
                    if (!b){
                        //b==false
                        log.info("token error");
                        currentContext.setSendZuulResponse(false);
                        ZuulResultVoUtils.sendErrorResultVo(Const.ERRORCODE,"您的Token不正确");
                    }
                } catch (Exception e) {
                    currentContext.setSendZuulResponse(false);
                    ZuulResultVoUtils.sendErrorResultVo(Const.ERRORCODE,"您输入的Token不合法");
                }
            }
    
    
            return null;
        }
    
    
    
    
    }
    
    
    • 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

    发送工具类

    package com.qf.lawer.utils;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.netflix.zuul.context.RequestContext;
    import com.qf.lawer.vo.ResultVo;
    
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class ZuulResultVoUtils {
        public static void sendErrorResultVo(Integer code,String message){
            RequestContext currentContext = RequestContext.getCurrentContext();
            HttpServletResponse response = currentContext.getResponse();
            response.setContentType("application/json;charset=utf-8");
            ResultVo resultVo = ResultVo.error(code, message);
            ObjectMapper mapper = new ObjectMapper();
            String s=null;
            try {
               s = mapper.writeValueAsString(resultVo);
                response.getWriter().println(s);
            } catch (Exception e) {
                e.printStackTrace();
              }
    
    
        }
    }
    
    
    • 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

    9.跨域问题,无法拿到请求头怎么办

    CORS(跨域资源共享):在服务器端设置响应头,允许特定的域或所有域的请求访问资源。可以通过在响应头中添加Access-Control-Allow-Origin字段来指定允许的域,例如Access-Control-Allow-Origin: http://example.com。你还可以设置其他相关的CORS响应头字段,如Access-Control-Allow-Methods和Access-Control-Allow-Headers来控制允许的请求方法和请求头。

    10.在springboot中使用servlet

    Servlet

    package com.qf.HomeWork.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebServlet("/h1")
    public class HelloServlet extends HttpServlet {
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=utf-8");
            String username = req.getParameter("username");
            System.out.println(username);
            resp.getWriter().println("Hello from Servlet:"+username);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在主启动类上面加上注解

    @ServletComponentScan//扫描启动类所同级目录下所有目录下标记了@WebServlet("/h1") 的类  servlet
    
    • 1

    @ServletComponentScan注解会将带有@WebServlet@WebFilter@WebListener`注解的类自动扫描并注册到Spring Boot的IOC容器中。

    11.在springMVC中/*与/的完全理解

    @RequestMapping("/test")
    public String test(Model model){
    
        System.out.println("进入了test方法");
        //他会先去找动态的资源,找不到再去找静态资源,再找不到就404;动态优先级比静态高,
        // 所以 /* 和/的区别, 就是/*包括jsp  /不包括jsp,因为jsp不是静态资源   ,所以如果把他作为dispatcherServlet 包含的话
        //他会按照动态资源找,找完以后,不会去静态资源找,所以爆404,但是如果用/,不让jsp页面走dispatcherServlet
        //他会去servlet容器下去寻找 对应的jsp页面,原因是jsp本身就是一个servlet。
        
        //templeaf模板它是集成了html静态资源所以转发的是html里会被当成静态资源,所以可以走dispatcherServlet
        //在dispatcherServlet做了静态资源的判断,常见的 html,css,js后缀的都是静态资源,但是都会先走一遍动态匹配,如果没匹配上,是这些静态资源后缀的,才交给servlet容器去找静态资源。
        
       return "/a.html";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    12.用户购物车,怎么判断是自己的购物车

    在用户登录的时候,会把用户的登录信息放在本地的cookie中,是设置时间的,不会随着浏览器的关闭而关闭,访问购物车的时候,登录信息还在,会查用户id为几的 购物车下有哪些商品,价格多少。过一段时间,如果用户没有访问的话,就清空一次该用户的购物车!

    因为cookie本身存储在本地,本身是安全的。所以它每次访问一次请求会把cookie带入到后端服务器,验证通过是登录后的状态,服务器会从jwt里取出用户id查询它的订单或者购物车信息。

    13.域名与cookie

    浏览器在不同域名下会将Cookie分别存储和管理。

    Cookie是与域名相关联的,每个域名都有自己的Cookie存储空间。当浏览器接收到来自不同域名的响应时,会将每个域名下的Cookie分别保存起来,并在之后的请求中将相应域名下的Cookie信息发送给服务器。

    这意味着,不同域名之间的Cookie是相互独立的,它们之间不能共享。例如,当你访问example.com和example.net这两个域名时,浏览器会分别存储和管理这两个域名下的Cookie,它们之间不会相互干扰。

    这种机制可以实现跨域访问的安全性。由于不同域名下的Cookie是相互独立的,因此一个域名下的JavaScript代码不能直接访问另一个域名下的Cookie,这可以防止恶意代码窃取其他域名下的Cookie信息。

    14.跨域问题

    跨域,如果浏览器直接访问服务器,是因为访问域名与目标服务器域名同源,所以不会产生跨域问题,

    但是如果客户端所在的域,与服务器所在的域不同源,然后客户端发送ajax请求,来访问服务器,这会产生跨域问题。

    因为比如 baidu与csdn域名不一样,所以它们两个的cookie都是相互独立的,拿不到对方的cookie,但是如果baidu的服务器允许csdn跨域请求,csdn的客户端可以将请求发送到baidu服务器来获取,baidu服务器的信息。

  • 相关阅读:
    Java基础(一)
    第一季:12Linux常用服务类相关命令【Java面试题】
    乐高式扩展:在Seal软件供应链防火墙中轻松集成代码规范工具
    人工智能聊天机器人如何帮助您实现工作与生活的平衡
    Redis 中新的三种数据类型
    K8S常见的持久化(存储)方案用法详解
    java中类加载与双亲委派机制
    2023长春理工大学计算机考研信息汇总
    go-zero&go web集成gorm实战
    重装系统后笔记本电脑无线wifi怎么连接
  • 原文地址:https://blog.csdn.net/qq_53374893/article/details/133413537