Session和Cookie的使用

在Web应用程序中,我们经常要跟踪用户身份。当一个用户登录成功后,如果他继续访问其他页面,Web程序如何才能识别出该用户身份?
因为HTTP协议是一个无状态协议,即Web应用程序无法区分收到的两个HTTP请求是否是同一个浏览器发出的。为了跟踪用户状态,服务器可以向浏览器分配一个唯一ID,并以Cookie的形式发送到浏览器,浏览器在后续访问时总是附带此Cookie,这样,服务器就可以识别用户身份。

Session
我们把这种基于唯一ID识别用户身份的机制称为Session。每个用户第一次访问服务器后,会自动获得一个Session ID。如果用户在一段时间内没有访问服务器,那么Session会自动失效,下次即使带着上次分配的Session ID访问,服务器也认为这是一个新用户,会分配新的Session ID。
JavaEE的Servlet机制内建了对Session的支持。我们以登录为例,当一个用户登录成功后,我们就可以把这个用户的名字放入一个HttpSession对象,以便后续访问其他页面的时候,能直接从HttpSession取出用户名:

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password= req.getParameter("password");
        System.out.println(username+" : "+password);
        if("admin".equals(username)&&"123".equals(password)){
            //登录成功
            //记录当前登录状态
            req.getSession().setAttribute("currentUser",username);
            resp.sendRedirect("/index");
        }else{
            resp.sendError(404);
        }
    }
}

上述LoginServlet在判断用户登录成功后,立刻将用户名放入当前HttpSession

HttpSession session = req.getSession();
session.setAttribute("currentUser", username);

如果用户已登录,可以通过访问/logout登出。登出逻辑就是从HttpSession中移除用户相关信息

@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getSession().removeAttribute("currentUser");
        resp.sendRedirect("/index");
    }
}

服务器识别Session的关键就是依靠一个名为JSESSIONID的Cookie。在Servlet中第一次调用req.getSession()时,Servlet容器自动创建一个Session ID,然后通过一个名为JSESSIONID的Cookie发送给浏览器:
这里要注意的几点是:

  • JSESSIONID是由Servlet容器自动创建的,目的是维护一个浏览器会话,它和我们的登录逻辑没有关系;
  • 登录和登出的业务逻辑是我们自己根据HttpSession是否存在一个"user"的Key判断的,登出后,Session ID并不会改变;
  • 即使没有登录功能,仍然可以使用HttpSession追踪用户,例如,放入一些用户配置信息等。
  • 使用Cookie机制可以实现Session外,还可以通过隐藏表单、URL末尾附加ID来追踪Session。这些机制很少使用,最常用的Session机制仍然是Cookie。

使用Session时,由于服务器把所有用户的Session都存储在内存中,如果遇到内存不足的情况,就需要把部分不活动的Session序列化到磁盘上,这会大大降低服务器的运行效率,因此,放入Session的对象要小,通常我们放入一个简单的User对象就足够了:

public class User {
    public long id; // 唯一标识
    public String email;
    public String name;
}

Cookie
实际上,Servlet提供的HttpSession本质上就是通过一个名为JSESSIONID的Cookie来跟踪用户会话的。除了这个名称外,其他名称的Cookie我们可以任意使用。
如果我们想要设置一个Cookie,例如,记录用户选择的语言,可以编写一个LanguageServlet

@WebServlet(urlPatterns = "/pref")
public class LanguageServlet extends HttpServlet {
    private static final Set<String> LANGUAGES = Set.of("en", "zh");
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String lang = req.getParameter("lang");
        if (LANGUAGES.contains(lang)) {
            // 创建一个新的Cookie:
            Cookie cookie = new Cookie("lang", lang);
            // 该Cookie生效的路径范围:
            cookie.setPath("/");
            // 该Cookie有效期:
            cookie.setMaxAge(8640000); // 8640000秒=100天
            // 将该Cookie添加到响应:
            resp.addCookie(cookie);
        }
        resp.sendRedirect("/");
    }
}

创建一个新Cookie时,除了指定名称和值以外,通常需要设置setPath("/"),浏览器根据此前缀决定是否发送Cookie。如果一个Cookie调用了setPath("/user/"),那么浏览器只有在请求以/user/开头的路径时才会附加此Cookie。通过setMaxAge()设置Cookie的有效期,单位为秒,最后通过resp.addCookie()把它添加到响应。
如果访问的是https网页,还需要调用setSecure(true),否则浏览器不会发送该Cookie。
因此,务必注意:浏览器在请求某个URL时,是否携带指定的Cookie,取决于Cookie是否满足以下所有要求:

  • URL前缀是设置Cookie时的Path;
  • Cookie在有效期内;
  • Cookie设置了secure时必须以https访问。

如果我们要读取Cookie,例如我们在ParseCookies读取名为lang的Cookie以获取用户设置的语言

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/parseCookies")
public class ParseCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie [] cookies = req.getCookies();
        String currentLang= "EN"; //set default
        if(cookies!=null){
            for (Cookie cookie : cookies) {
                System.out.println(cookie.getName());
                if(cookie.getName().equals("lang")){
                    System.out.println(cookie.getValue());
                }
            }
        }
        resp.sendRedirect("/");
    }
}

可见,读取Cookie主要依靠遍历HttpServletRequest附带的所有Cookie。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值