Cookie,Session与Token
参考资料
水平有限,欢迎交流!仅做学习交流使用
一定要看,非常透彻!【Cookie、Session、Token究竟区别在哪?如何进行身份认证,保持用户登录状态?】
黑马jwt详解
Javaweb程序设计与项目案例 郭煦
直接上结论
共同点
Cookie,Session与Token 三者都实现了 Http 无状态这一特点的补充,通过存储在不同硬件或不同算法加密来存储用户状态
不同点
Cookie 将用户状态保存在客户端(如浏览器)
Session 将用户状态保存在服务器端
Cookie 详解
Cookie 是服务器发送到用户浏览器并保存在本地的小块数据。Cookie 由浏览器(客户端)管理,每次请求都会自动发送到服务器。需要注意的是,由于隐私和安全原因,许多现代浏览器对第三方 Cookie(即由不同于当前浏览网站的域发送的 Cookie)进行了限制。此外,一些用户也可能选择禁用 Cookie,这可能会影响依赖于 Cookie 的功能正常运作。
特点
- 存储限制:每个域名下可以存储的 Cookie 数量有限,通常不超过 20 个。
- 大小限制:每个 Cookie 的大小通常限制在 4 KB 左右。
- 安全问题:Cookie 可以被客户端篡改,因此不适用于存储敏感信息。
- 作用域:Cookie 可以设置作用域,例如仅在当前域名下有效。
分类
此外,Cookie 还可以分为会话 Cookie 和持久性 Cookie:
会话 Cookie
- 会话 Cookie 只在用户与网站交互期间存在(存放在客户端内存),并且在用户关闭浏览器时就会被删除。
持久性 Cookie
- 持久性 Cookie 有一个明确的过期日期,即使用户关闭浏览器后,Cookie 也会被保留 (存放在客户端硬盘),直到过期日期为止。
用途
- 会话管理:通过 Cookie 识别用户身份,实现用户登录状态的持久化。
- 个性化设置:存储用户偏好设置,如语言、主题等。
流程
Cookies 是网站用来在用户浏览器上存储小量数据的一种机制。它们用于跟踪用户的活动,保存用户的偏好设置,以及实现其他功能性的需求。下面是 Cookie 的基本工作流程:
- 用户首次访问一个网站(此时不存在 Cookie),浏览器向服务器发送请求。
- 服务器处理请求,并根据需要将数据发送给浏览器,同时可以附加一个或多个 Cookie。Set-Cookie: name = value
- 浏览器接收到响应后,会检查是否有任何 Cookie 信息,并存储这些 Cookie 在本地硬盘上。
- 当浏览器后续请求同一站点时,浏览器都会自动包含这个 Cookie 在 HTTP 请求头中 发送给服务器。
- 服务器根据接收到的 Cookie 来识别用户,从而提供个性化的网页内容或者恢复用户的偏好设置等。
常用方法
案例
import java.io.IOException;
import java.io.PrintWriter;
//tomcat版本10.1 用的jakarta,版本较低可将jakarta换为javax!
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/CookieDemo")
public class CookieDemo extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
PrintWriter out = resp.getWriter();
Cookie[] cookies = req.getCookies();
resp.setContentType("text/html;charset = UTF-8");
boolean flag = false;
if(cookies!=null) {
for (Cookie cookie : cookies) {
if(cookie.getName().equals("ip")) {
out.write("welcome!上次ip为:"+ cookie.getValue());
flag = true;
break;
}
}
if(!flag) {
out.write("欢迎新用户!");
Cookie c = new Cookie("ip",req.getRemoteAddr());
c.setMaxAge(1*60);//单位:s 这里为1min
resp.addCookie(c);
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
super.doPost(req, resp);
}
}
Session 详解
Session 是服务器端用来跟踪用户会话的一种机制。当用户首次访问服务器时,服务器会创建一个 Session,并生成一个唯一的 Session ID,这个 ID 通常会存储在 Cookie 中,随请求发送回服务器。
特点:
- 存储位置:Session 数据存储在服务器端,安全性较高。
- 存储限制:由于存储在服务器,理论上没有大小限制,但会占用服务器资源。
- 生命周期:可以设置 Session 的过期时间,过期后自动销毁。
- 作用域:通常与浏览器窗口或标签页的生命周期相关。
用途:
- 用户身份验证:存储用户登录后的会话信息。
- 购物车:存储用户的购物车数据。
常用功能
流程
- 用户发起请求:当用户打开浏览器并访问一个网站时,浏览器向服务器发送一个 HTTP 请求。
- 服务器创建 Session:服务器接收到请求后,如果发现这是一个新用户(即没有可用的 Session ID),则会创建一个新的 Session 并分配一个唯一的 Session ID 给这个用户。如果用户之前已经有过会话,则服务器会从请求中提取已有的 Session ID。
- 存储 Session 数据:服务器会在服务器端存储与 Session ID 相关的信息,比如用户的偏好设置、购物车中的商品或者其他状态信息。
- 返回响应和 Session ID:服务器处理完请求后,会将处理结果和 Session ID 一起返回给客户端。通常,Session ID 是通过 Cookie 或者 URL 参数传递给客户端的。
- 客户端存储 Session ID:客户端(通常是浏览器)接收到响应后,会存储 Session ID(如果通过 Cookie 传递的话)。对于后续请求,浏览器会自动将 Session ID 发送给服务器。
- 使用 Session 数据:对于用户后续的请求,服务器会读取 Session ID,并查找与此 ID 相关联的数据来个性化用户的体验或继续处理用户的请求。
- Session 的结束:Session 通常会在一定时间后因无活动而超时,或者当用户显式地登出时结束。服务器会清除与该 Session ID 相关的数据。
补充说明
Session 的创建
Session 的超时时间设置
设置 Session 超时可以通过多种方式来实现,这取决于使用的编程语言和框架。以下是三种常见的方法来设置 Session 的超时时间:
1. Tomcat 全局配置
2. 通过配置文件设置
许多 Web 应用框架允许你在配置文件中设置 Session 的超时时间。这种方式的好处是可以全局控制所有 Session 的超时时间,而无需修改代码。
示例:jsp 项目中web. Xml 中的配置
<session-config>
<session-timeout>2</session-timeout>
</session-config>
示例:Java Spring Boot 中的配置
在 Spring Boot 中,可以通过 application.properties
或 application.yml
文件来设置 Session 的超时时间:
server.tomcat.session-timeout=30 # 单位为分钟
3. 在代码中动态设置
在某些情况下,你可能希望针对不同的用户或操作设置不同的 Session 超时时间。这时可以在代码中动态地设置超时时间。
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class SessionServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 获取 HttpSession 对象
HttpSession session = request.getSession();
// 设置 Session 的超时时间为 30 分钟(以毫秒为单位)
long timeoutInMillis = 30 * 60 * 1000; // 30 minutes
session.setMaxInactiveInterval(timeoutInMillis / 1000); // 注意这里需要转换成秒
// 输出确认信息
response.getWriter().println("Session timeout set to " + session.getMaxInactiveInterval() + " seconds.");
}
}
4. 使用中间件或过滤器,拦截器(本质还是 3)
对于一些框架,如 Node. Js 或者 Ruby on Rails,你可以编写中间件或者过滤器来控制 Session 的超时时间。
在 Java Web 开发中,Filter 和 Interceptor 是两种不同的机制,它们都可以用来拦截请求并在请求处理前后执行某些操作。尽管 Filter 和 Interceptor 都可以用来实现类似的功能,但是它们的应用场景和配置方式略有不同。
使用 Filter 设置 Session 的超时时间
Filter 是 Servlet 规范的一部分,可以直接在 Servlet 容器中使用。如果你想在 Filter 中设置 Session 的超时时间,可以通过以下步骤实现:
- 创建 Filter 类:首先创建一个实现了
javax.servlet.Filter
接口的类。 - 重写
doFilter
方法:在这个方法中,你可以获取 HttpSession 并设置其超时时间。 - 注册 Filter:在 web. Xml 中或者通过注解的方式注册你的 Filter。
示例代码
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter(urlPatterns = {"/*"})
public class SessionTimeoutFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化方法,可以在这里进行一些初始化工作
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取 HttpSession 对象
HttpSession session = httpRequest.getSession();
// 设置 Session 的超时时间为 30 分钟(以秒为单位)
int timeoutInSeconds = 30 * 60; // 30 minutes
session.setMaxInactiveInterval(timeoutInSeconds);
// 执行下一个 Filter 或者目标资源
chain.doFilter(request, response);
}
@Override
public void destroy() {
// 销毁方法,可以在这里进行一些清理工作
}
}
使用 Interceptor 设置 Session 的超时时间
Interceptor 是特定框架(如 Spring MVC 或 Struts 2)提供的机制,用于拦截请求并在请求处理前后执行操作。如果你使用的是 Spring MVC,可以通过定义一个 HandlerInterceptor
来设置 Session 的超时时间。
示例代码
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class SessionTimeoutInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 获取 HttpSession 对象
HttpSession session = request.getSession();
// 设置 Session 的超时时间为 30 分钟(以秒为单位)
int timeoutInSeconds = 30 * 60; // 30 minutes
session.setMaxInactiveInterval(timeoutInSeconds);
return true; // 返回 true 表示继续处理请求
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
// 在请求处理之后执行的操作
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 在请求完成之后执行的操作
}
}
注册 Interceptor
要让 Interceptor 生效,还需要在 Spring MVC 的配置类中注册它:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SessionTimeoutInterceptor());
}
}
Session 的销毁
情形一
Session 超时
情形二
调用 HttpSession 的 invalidate ()
情形三
会话式 session 保存 session-id 时,用户关闭浏览器
案例
![[Pasted image 20240929213640.png]]
login. jsp 文件如下
<%@ page contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Login</title>
</head>
<body>
<fieldset>
<legend>登录</legend>
<!-- 表单数据的提交方式为POST -->
<form action="SessionDemoServlet" method="post">
<table cellpadding="2" align="center">
<tr>
<td align="right">用户名:</td>
<td>
<!-- 1.文本输入框控件 -->
<input type="text" name="username" />
</td>
</tr>
<tr>
<td align="right">密码:</td>
<!-- 2.密码输入框控件 -->
<td><input type="password" name="password" /></td>
</tr>
<tr>
<td colspan="2" align="center">
<!-- 3.提交按钮控件 -->
<input type="submit" value="登录" />
<!-- 4.重置按钮控件,单击后会清空当前form -->
<input type="reset" value="重填" />
</td>
</tr>
</table>
</form>
</fieldset>
</body>
</html>
welcome. jsp 如下
<%@ page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
欢迎<%= session.getAttribute("name") %>,登陆成功!
<a href="LogoutServlet">退出</a>
</body>
</html>
SessionDemoServlet. java
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
@WebServlet("/SessionDemoServlet")
public class SessionDemoServlet extends HttpServlet{
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException {
response.setContentType("text/html;charset = utf-8");
String userName = request.getParameter("username");
String password = request.getParameter("password");
if(userName.equals("芩离")&&password.equals("123456")) {//改成自己的!
HttpSession session = request.getSession();
session.setAttribute("name", userName);
response.sendRedirect("welcome.jsp");
}
else{
PrintWriter out = response.getWriter();
out.print("用户名或密码错误,返回<a href=\'login.jsp\'>登录</a>");
response.setHeader("refresh","3;url = login.jsp");//失败后三秒跳转登录页
}
}
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
super.doGet(request, response);
}
}
LogoutServlet. java
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.removeAttribute("name");
session.invalidate();
resp.sendRedirect("login.jsp");
}
}
Token 详解
Token 是一种无状态的认证机制,通常用于 RESTful API。Token 通常是一个加密的字符串,包含了用户的身份信息和一些验证信息。
特点:
- 无状态:服务器不需要存储 Session 信息,每次请求都独立验证 Token。
- 安全性:Token 可以包含过期时间,减少被盗用的风险。
- 跨域:Token 可以跨域使用,适合分布式系统。
- 自定义:Token 的内容可以根据需要自定义。
常见类型:
- JWT(JSON Web Token):一种开放标准(RFC 7519),用于在网络应用环境间安全地传递声明。
- OAuth:一个行业标准的协议,允许用户提供一个令牌来访问他们存储在另外的服务提供者上的信息,而无需将他们的凭据提供给第三方应用。
用途:
- API 认证:用于保护 RESTful API,确保请求者的身份。
- 单点登录(SSO):允许用户使用一套凭证访问多个系统。
jwt 工具类及其使用
依赖
要想使用JWT令牌,需要先引入JWT的依赖:
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
工具类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
/**
* 生成jwt
* 使用Hs256算法, 私匙使用固定秘钥
*
* @param secretKey jwt秘钥
* @param ttlMillis jwt过期时间(毫秒)
* @param claims 设置的信息
* @return
*/
public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
// 指定签名的时候使用的签名算法,也就是header那部分
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
// 生成JWT的时间
long expMillis = System.currentTimeMillis() + ttlMillis;
Date exp = new Date(expMillis);
// 设置jwt的body
JwtBuilder builder = Jwts.builder()
// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
.setClaims(claims)
// 设置签名使用的签名算法和签名使用的秘钥
.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
// 设置过期时间
.setExpiration(exp);
return builder.compact();
}
/**
* Token解密
*
* @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
* @param token 加密后的token
* @return
*/
public static Claims parseJWT(String secretKey, String token) {
// 得到DefaultJwtParser
Claims claims = Jwts.parser()
// 设置签名的秘钥
.setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
// 设置需要解析的jwt
.parseClaimsJws(token).getBody();
return claims;
}
}
校验过滤器的注册
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired
private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
/**
* 注册自定义拦截器
*
* @param registry
*/
protected void addInterceptors(InterceptorRegistry registry) {
log.info("开始注册自定义拦截器...");
registry.addInterceptor(jwtTokenAdminInterceptor)
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin/employee/login");
}
}
令牌校验
import com.sky.constant.JwtClaimsConstant;
import com.sky.context.BaseContext;
import com.sky.properties.JwtProperties;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* jwt令牌校验的拦截器
*/
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
/**
* 校验jwt
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断当前拦截到的是Controller的方法还是其他资源
if (!(handler instanceof HandlerMethod)) {
//当前拦截到的不是动态方法,直接放行
return true;
}
//1、从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());
//2、校验令牌
try {
log.info("jwt校验:{}", token);
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
log.info("当前员工id:{}", empId);
BaseContext.setCurrentId(empId);
//3、通过,放行
return true;
} catch (Exception ex) {
//4、不通过,响应401状态码
response.setStatus(401);
return false;
}
}
}
Controller层
@PostMapping("/login")
@ApiOperation(value = "员工登录")
public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
log.info("员工登录:{}", employeeLoginDTO);
Employee employee = employeeService.login(employeeLoginDTO);
//登录成功后,生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
.id(employee.getId())
.userName(employee.getUsername())
.name(employee.getName())
.token(token)
.build();
return Result.success(employeeLoginVO);
}
Service层
public Employee login(EmployeeLoginDTO employeeLoginDTO) {
String username = employeeLoginDTO.getUsername();
String password = employeeLoginDTO.getPassword();
//1、根据用户名查询数据库中的数据
Employee employee = employeeMapper.getByUsername(username);
//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
if (employee == null) {
//账号不存在
throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
}
//密码比对
// 对前端明文密码进行md5加密,然后再进行比对
password = DigestUtils.md5DigestAsHex(password.getBytes());//md5加密
if (!password.equals(employee.getPassword())) {
//密码错误
throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
}
if (Objects.equals(employee.getStatus(), StatusConstant.DISABLE)) {
//账号被锁定
throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
}
//3、返回实体对象
return employee;
}
Mapper层
@Select("select * from employee where username = #{username}")
Employee getByUsername(String username);
Cookie,Session与Token的更多相关文章
- Cookie Session 与Token
由于HTTP是一种无状态的协议,服务器端无法知道用户与客户端交互的状态,比如如果一个用于之前已经访问过该服务器,服务器无法知道该用户是第二次访问,Session和Cookie都是用来保存用户与后端服务 ...
- 存储机制 cookie session jwt token
cookieCookie的诞生 由于HTTP协议是无状态的,而服务器端的业务必须是要有状态的.Cookie诞生的最初目的是为了存储web中的状态信息,以方便服务器端使用.比如判断用户是否是第一次访问网 ...
- Cookie.Session到Token和JWT
一.session和cookie: 现在一般都是session和cookie一起用,一起提.但是他们俩其实不是一定要在一起. session的产生原因是,http协议是无状态的 这就导致了,不同的用户 ...
- cookie,session和token的概念以及区别
cookie: 采用客户端保存状态的方案: cookie的组成:名字,值过去时间,路径以及域: 没有设置时间:随着浏览器的打开和关闭决定: 设置了时间:浏览器就会把cookie保存在硬盘上,根据时间来 ...
- cookie、session与token
一.详述概念 1.Cookie机制 cookie机制是采用在客户端保持状态的方案(cookie的作用就是为了解决HTTP协议无状态的缺陷所作的努力).cookie的使用是由浏览器按照一定的原则在后台自 ...
- cookie,session,token的定义及区别
参考了很多文章总结的. 1.cookie(储存在用户本地终端上的数据) 服务器生成,发送给浏览器,浏览器保存,下次请求同一网站再发送给服务器. 2.session(会话) a.代表服务器与浏览器的一次 ...
- cookie, session, token 是什么 以及相应的安全考量
Cookie cookie 最常见的是用来保存一些账号信息,比如下图里的 记住账号 就是记录到了cookie里面 cookie 更主要的是针对和server通信的,我们知道http 是无状态的,那如果 ...
- cookie、session和token
https://zhuanlan.zhihu.com/p/25495290?utm_source=wechat_session&utm_medium=social 一.cookie 众所周知, ...
- Cookie、Session 和 Token区别
1 Cookie.Session 和 Token 都是用来做持久化处理的,目的就是让客户端和服务端相互认识.Http 请求默认是不持久的没有状态的,谁也不认识谁. 2 Cookie: 是存放在客户 ...
- 为什么你学不会递归?告别递归,谈谈我的一些经验 关于集合中一些常考的知识点总结 .net辗转java系列(一)视野 彻底理解cookie,session,token
为什么你学不会递归?告别递归,谈谈我的一些经验 可能很多人在大一的时候,就已经接触了递归了,不过,我敢保证很多人初学者刚开始接触递归的时候,是一脸懵逼的,我当初也是,给我的感觉就是,递归太神奇了! ...
随机推荐
- 文章学习|开放,让5G网络更智能
学习文章:开放,让5G网络更智能 介绍 从2G到5G,网络在不断发展,通信行业的生态系统在不断演进,运营商的角色也发生着改变. 在2G和3G时代,运营商作为服务提供商为用户提供通信业务和互联网业务,获 ...
- Java线程的安全问题
当多个线程同时访问同一资源(变量,文件,记录),如果只有读操作,则不会有线程安全问题,如果有读和写操作,则会产生线程安全问题,必须保证共享数据同一时刻只能有同一个线程操作.Java采取的办法是sync ...
- C# 性能优化 --- Lazy<T> 用法学习
参考原文:https://kb.cnblogs.com/page/99182/ 延迟实例化,对于需要创建大量对象,而又不需要立即使用的场景非常有用.一下实例说明了Lazy<T>的用法. u ...
- QStringListModel的使用
主要为 :添加.插入.修改.删除.清空等操作 例子:本例子中QListView 没有做任何处理,只是拖放至ui文件,设置了布局 MainWindow.h #ifndef MAINWINDOW_H #d ...
- 分块-byx
Update:2025.5.25 树状数组是基于二进制划分与倍增的思想,线段树基于分治的思想.之所以能够高效修改和查询,就是把序列分成了大大小小的"段",花费额外(增加空间,空间换 ...
- Hadoop - HDFS 概述
什么是HDFS HDFS的优缺点 HDFS的文件块大小 HDFS的写数据流程 HDFS的副本配置策略 HDFS读数据的流程 什么是HDFS HDFS(Hadoop Distributed File S ...
- MySQL 8.0 语法记录
SQL又杂又烦,记不住,网上搜到的语句还未必正确.这里做一个Record 基本操作 数据库操作 数据表操作 create index [索引名] on [表名]([列名]); /* 以选定列为索引信息 ...
- WordPress域名更换小记
WordPress域名更换记录 1.准备工作 在开始之前,要有一个全面的备份,包括网站的文件和数据库.这确保了如果出现问题,你可以恢复到更改之前的状态.不然中间卡壳直接连后台都打不开了,只能重装. ...
- Basics of using bash, and shell tools for covering several of the most common tasks
Basics of using bash, and shell tools for covering several of the most common tasks Introduction M ...
- selenium自动化测试-登录网站用户
昨天学习了selenium自动化测试工具的入门,知道了Selenium是用于自动化控制浏览器做各种操作,打开网页,点击按钮,输入表单等等. 今天学习通过selenium自动化测试工具自动登录某网站用户 ...