• Spring cookie 实战


    测试环境搭建

    使用Springboot构建web server, 在测试方法中打印接收的cookie。

    @RestController
    @RequestMapping("/register/test/service")
    public class TestService {
        private Log logger = LogFactory.getLog(TestService.class);
    //   使用HttpServletRequest 获取cookie
        @RequestMapping(value = "/ping", method = RequestMethod.GET)
        public Response ping(HttpServletRequest httpRequest, HttpServletResponse httpServletResponse) throws IOException {
    
            Cookie[] cookies = httpRequest.getCookies();
            logger.info("cookies info"+JsonUtils.toJson(cookies));
            //Mice
            return new Response().setData("OK!!!");
        }
    }
    

    Postman开起Interceptor,在如下图所示

    输URL: http://localhost:8080/register/test/service/ping
    Header:Cookie:test=hello(name= test, value=hello的cookie)

    测试结果

    返回cookie, Cookie在使用期限内,一值存在,在服务器端可以修改cookie的生命周期

    Cookie的几点常识

    //文本数据明文,登陆分配,用于后台校验识别不同的用户

    简单地说,cookie就是浏览器储存在用户电脑上的一小段文本文件。cookie 是纯文本格式,不包含任何可执行的代码。一个web页面或服务器告知浏览器按照一定规范来储存这些信息,并在随后的请求中将这些信息发送至服务器,Web服务器就可以使用这些信息来识别不同的用户。大多数需要登录的网站在用户验证成功之后都会设置一个cookie,只要这个 cookie 存在并可以,用户就可以自由浏览这个网站的任意页面。再次说明,cookie 只包含数据,就其本身而言并不有害。

    //区分访问web服务器的来源,维护状态
    为什么需要Cookie?
    因为HTTP协议是无状态的,对于一个浏览器发出的多次请求,WEB服务器无法区分是不是来源于同一个浏览器。所以,需要额外的数据用于维护会话。 Cookie 正是这样的一段随HTTP请求一起被传递的额外数据。

    //存储大小受限
    Cookie 的限制。 大多数浏览器支持最大为 4096 字节的 Cookie。由于这限制了 Cookie 的大小,最好用 Cookie 来存储少量数据,或者存储用户 ID 之类的标识符。用户 ID 随后便可用于标识用户,以及从数据库或其他数据源中读取用户信息。 浏览器还限制站点可以在用户计算机上存储的 Cookie 的数量。大多数浏览器只允许每个站点存储 20 个 Cookie;如果试图存储更多 Cookie,则最旧的 Cookie 便会被丢弃。有些浏览器还会对它们将接受的来自所有站点的 Cookie 总数作出绝对限制,通常为 300 个。

    详细描述见下文
    http://bubkoo.com/2014/04/21/http-cookies-explained/

    Java Spring Read Cookie

    使用CookieVlaue标签来获取指定name的Cookie

    //   使用HttpServletRequest 获取cookie
    @RequestMapping(value = "/ping", method = RequestMethod.GET)
    public Response ping(@CookieValue("test") String fooCookie) throws IOException {
        //Mice
        return new Response().setData("OK, cookieValue=!!!" + fooCookie);
    }
    

    在上面的的代码中如果CooKie不存在,会抛出返回异常:

    {
      "timestamp": 1466584427218,
      "status": 400,
      "error": "Bad Request",
      "exception": "org.springframework.web.bind.ServletRequestBindingException",
      "message": "Missing cookie 'majun' for method parameter of type String",
      "path": "/register/test/service/ping"
    }
    

    可以通过设置默认值来解决这个异常,如果业务上不呈现这个异常的话!!

    使用HttpServletRequest可以获取Cookie列表

    Java Spring Create Cookie

    使用HttpServletResponse, Cookie类,

    //   使用HttpServletResponse增加cookie, cookie会返回给前端
    @RequestMapping(value = "/getCookie", method = RequestMethod.GET)
    public Response getCookie(HttpServletResponse httpServletResponse) throws IOException {
        Cookie cookie = new Cookie("majun", "xiaoya");
        cookie.setMaxAge(10); //设置cookie的过期时间是10s
        httpServletResponse.addCookie();
        return new Response().setData("allocate cookie success!!!");
    }
    

    如果创建的Cookie (name相同)已经存在,那么新的Cookie会覆盖老的cookie。

    可以在Postman看到Cookie的返回信息

    拦截器和Cookie

    **拦截器是什么? **
    拦截器的作用在于对处理器进行预处理和后处理,类似于filter。拦截器的原理详见:
    http://www.cnblogs.com/fangjian0423/p/springmvc-interceptor.html

    拦截器的使用场景
    1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
    2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
    3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
    4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
    5、OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。
    …………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。

    Springboot实现拦截器

    定义拦截面类

    package com.im.server.Interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Created by majun on 16/6/22.
     */
    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
    
            System.out.println(">>>MyInterceptor>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
            Cookie[] cookies = httpServletRequest.getCookies();
            if (cookies == null || cookies.length == 0) {
                throw new Exception("illegal Login");
            }
            try {
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals("USER_TOKEN")) {
                        //User user =
                        httpServletRequest.setAttribute("USER_TOKEN", "{name: GUHUA, age: 20}");
                        return true;
                    }
                }
                throw new Exception("illegal Login");
            } catch (Exception exp) {
                throw exp;
            }
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
            System.out.println(">>>MyInterceptor>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            System.out.println(">>>MyInterceptor>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
        }
    }
    

    配置拦截器:继承WebMvcConfigurerAdapter类即可

    package com.im.server.conf;
    
    import com.im.server.Interceptor.MyInterceptor;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    @Configuration
    public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/register/test/service/**");
            super.addInterceptors(registry);
        }
    
    }
    

    控制器中获取USER_TOKEN对应的用户内容

    //   使用HttpServletResponse增加cookie, cookie会返回给前端
    @RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)
    public Response getUser(HttpServletRequest httpServletRequest) throws IOException {
        Object user_token = httpServletRequest.getAttribute("USER_TOKEN");
        return new Response().setData(user_token);
    }
    

    测试结果

    下面的链接详细讲了Spring mvc拦截器的实现原理:
    http://www.cnblogs.com/fangjian0423/p/springmvc-interceptor.html

  • 相关阅读:
    centos 修改语言、时区
    去除 ufeff
    Docker介绍及使用
    消息队列
    数据结构与算法
    Haystack
    Python面向对象之魔术方法
    关于Redis处理高并发
    Redis
    RESTful规范
  • 原文地址:https://www.cnblogs.com/jun-ma/p/5679459.html
Copyright © 2020-2023  润新知