​Session 和 Cookie,你真的清楚了?看完再说!

从事 web 开发同学,相信对 session 和 cookie 都不会感到陌生,可是你真正理解 session 和 cookie 以及两者的区别吗?曾经面试过一个十年经验的开发竟然也回答的模棱两可,所以觉得有必要详细理一下。

在正式开始本文内容前,需要对JavaEE规范有一定的认识:

规范中的 servlet 是sun定义的用于开发服务端的接口,如HttpServletRequest、 Cookie、HttpSession等,但是实现由具体容器决定,比如 tomcat、jetty等。

下面正式开始今天内容,首先看下session 是什么?

 通常一次连接建立,默认服务器端就产生了一个会话,这个跟现实世界里打电话类似:一旦通话双方接通后就代表一次会话开始了。需要注意的是现实通话双发一旦挂断电话,就代表会话结束了,但是我们这里的 session 却是跨多个连接的!

我们再看下 cookie 的定义(wikipedia):

An HTTP cookie (also called web cookie, Internet cookie, browser cookie, or simply cookie) is a small piece of data sent from a website and stored on the user’s computer by the user’s web browser while the user is browsing.

翻译过来一句话:cookie是由服务端发送过来,浏览器存储的数据片。

定义我们清楚了,下面看 session 和 cookie 的关系:session 创建后会将 session id (准确名称 JSESSIONID) 放入 cookie 中存储在浏览器中。这是大家印象里的,但事实是:不手动调用 获取 session 方法, 并不会产生 session 对象,也不会创建cookie!

看如下代码:


@GetMapping("/versions")
public ResponseEntity selectAll(@RequestParam("device_type") String device_type, HttpServletRequest request) {
    System.out.println(request.getClass());
    // cookie为空
    Cookie[] cookies = request.getCookies();
    if(cookies !=null) {
        Arrays.stream(cookies).forEach((cookie) ->
                log.info(cookie.getName() + " : " + cookie.getValue())
        );
    }


    OTAVersionExample example = new OTAVersionExample();
    example.createCriteria().andDevice_typeEqualTo(device_type);
    List<OTAVersion> otaVersionList = otaVersionMapper.selectByExample(example);
    return Ok.newOk(otaVersionList, HttpStatus.OK);
}

以上代码,无论你访问多少次,在控制台 Request headers 始终没有cookie, 后台代码也不会打印 cookie 信息。

现修改代码:

@GetMapping("/versions")
public ResponseEntity selectAll(@RequestParam("device_type") String device_type, HttpServletRequest request) {
    System.out.println(request.getClass()); // class org.eclipse.jetty.server.Request

    HttpSession session = request.getSession(); // 手动创建session,cookie才有值
    Cookie[] cookies = request.getCookies();
    if(cookies !=null) {
        Arrays.stream(cookies).forEach((cookie) ->
// JSESSIONID : 1D836B3B8D71A92D23305A62A7A3F929log.info(cookie.getName() + " : " + cookie.getValue()));}OTAVersionExample example = new OTAVersionExample();example.createCriteria().andDevice_typeEqualTo(device_type);List<OTAVersion> otaVersionList = otaVersionMapper.selectByExample(example);return Ok.newOk(otaVersionList, HttpStatus.OK);}

首次请求, 没有 cookie信息;刷新后, Request headers 中多了一句:

Cookie:: JSESSIONID=1D836B3B8D71A92D23305A62A7A3F929

深入源码,看下 getSession 方法到底做了什么:

 org.eclipse.jetty.server.Request

public class Request implements HttpServletRequest
{

    ....

    @Override
    public HttpSession getSession()
    {
        return getSession(true);
    }

    @Override
    public HttpSession getSession(boolean create)
    {
        if (_session != null)
        {
            if (_sessionManager != null && !_sessionManager.isValid(_session))
                _session = null;
            else
                return _session;
        }

        if (!create)
            return null;

        if (getResponse().isCommitted())
            throw new IllegalStateException("Response is committed");

        if (_sessionManager == null)
            throw new IllegalStateException("No SessionManager");

        _session = _sessionManager.newHttpSession(this);
        HttpCookie cookie = _sessionManager.getSessionCookie(_session,getContextPath(),isSecure()); //为session添加cookie
        if (cookie != null)
            _channel.getResponse().addCookie(cookie); //看到了添加cookie到response消息中

        return _session;
    }
    .....

    @Override
    public HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure)
    {
        if (isUsingCookies())
        {
            String sessionPath = (_cookieConfig.getPath()==null) ? contextPath : _cookieConfig.getPath();
            sessionPath = (sessionPath==null||sessionPath.length()==0) ? "/" : sessionPath;
            String id = getNodeId(session);
            HttpCookie cookie = null;
            if (_sessionComment == null)
            {
                cookie = new HttpCookie(
                                        _cookieConfig.getName(), // JSESSIONID
                                        id,
                                        _cookieConfig.getDomain(),
                                        sessionPath,
                                        _cookieConfig.getMaxAge(),
                                        _cookieConfig.isHttpOnly(),
                                        _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure));
            }
            else
            {
                cookie = new HttpCookie(
                                        _cookieConfig.getName(),
                                        id,
                                        _cookieConfig.getDomain(),
                                        sessionPath,
                                        _cookieConfig.getMaxAge(),
                                        _cookieConfig.isHttpOnly(),
                                        _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure),
                                        _sessionComment,
                                        1);
            }

            return cookie;
        }
        return null;
    }

不解释了,看我在代码中添加的注释应该就清楚了。

最后小本子整理笔记:

  1. session 需要服务端新建后,将id放入cookie里发送到客户端,客户端下次请求放入头部传到服务器端来验证是否是同一会话。

  2. 如果不手动调用 session 的创建代码,浏览器端并没有显示 cookie,更看不到 JSESSIONID,浏览器不显示 cookie 

最近比较忙图片,趁着周五,加个班肝了这一篇。

祝大家周末愉快~

如果觉得还不错的话,关注、分享、在看, 原创不易,且看且珍惜~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【非典型Coder】

赏个鸡腿吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值