ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Cookie和Session的区别:从登录掉线到安全漏洞,一文搞懂

Cookie和Session的区别:从登录掉线到安全漏洞,一文搞懂 从登录掉线到安全漏洞Cookie和Session的区别你真的搞懂了吗但凡做过Web开发迟早会在登录模块上栽一次跟头——要么是用户反馈“明明登录了刷新一下就掉线”要么是后端同事盯着一串看不懂的加密字符串问你“这玩意儿到底存哪儿了”。这时候绕不开的两个词就是Cookie和Session。你可以在任何一个技术社区搜到大量对比但说实话能把这俩概念讲清楚的人不多能把它们在实际项目中用明白的人更少。这篇文章我会从两者底层的存储逻辑讲起掰开揉碎说清楚它们各自的工作机制、核心区别、登录场景下的协作方式再结合安全测试里常见的XSS攻击、Burp改Cookie、JMeter串联登录态这些实操场景把我踩过的坑和验证过的方案一并整理出来。适合刚入门的学生、转行做开发的初学者、写后端但对Web会话机制还比较含糊的同行参考。不夸张地说把这一篇吃透面试被问到“Cookie和Session的区别”时你能比大多数应聘者答得扎实。1. 先搞清楚它俩各自是什么1.1 Cookie住在浏览器里的“身份证复印件”Cookie是服务器下发、由浏览器本地保存的一小段文本数据。它的本质就是一个键值对集合比如usernamezhangsan或者tokenabc123。浏览器拿到这段数据后会按照域名、路径、过期时间等属性把它存下来之后每次请求这个域名下的资源时都会自动把对应的Cookie带在请求头里发给服务器。你可以把Cookie理解成一张“身份证复印件”——服务器把身份标识发给你你揣在口袋里每次进大门发HTTP请求时主动亮出来门卫服务器程序对着复印件核对一下你是谁。Cookie有几个关键属性会直接影响它的行为Expires和Max-Age控制过期时间Domain和Path控制作用范围Secure表示只允许HTTPS下传输HttpOnly表示禁止JavaScript读取。这些属性挂在一起构成了浏览器侧承载会话信息的完整机制。实际操作中很多人只关注键值对本身忽略了属性配置结果出现会话串号、Cookie丢失、被XSS窃取等一堆问题。1.2 Session留在服务器保险箱里的“档案袋”Session是一个存储在服务器端的概念它是服务器为每个用户会话临时创建的数据集合。当用户首次访问时服务器会生成一个唯一的会话ID通常叫Session ID并以此为key把用户相关的状态数据存进服务器内存、文件或者Redis这类外部存储中。会话ID会通过Cookie返回给浏览器浏览器后续请求携带这个ID服务器就能根据ID找到对应那份“档案袋”。还是用进门来打比方Session是服务台在你进门时给你开的“临时储物柜”——你有柜号Session ID你的东西放在服务台的柜子里你每次来只需要报柜号服务台帮你拿东西。柜号丢了或者柜子过期了你的东西就等于没了。Session最大的特点是数据存在服务端客户端只保存一个几乎无意义的随机ID。这意味着用户无法直接篡改Session里的业务数据安全性天然比Cookie直接存明文要强。但代价也明显——服务端要维护Session存储如果有多台服务器还要考虑Session共享或粘性会话的策略。1.3 为什么这两个东西总是被放在一起讨论因为它们本来就是一体的。Session的产生离不开Cookie的配合存储Session ID而Cookie能真正发挥作用也往往是作为Session的载体。你中有我、我中有你剥离开讲任何一方都是不完整的。举例来说Java Web默认的会话跟踪机制就是服务器通过HttpSession创建会话生成一个名为JSESSIONID的Cookie返回给浏览器。下次请求时Servlet容器从请求里取到JSESSIONID然后去Session池里找对应的HttpSession对象。这个过程相当透明所以很多初学者常年只使用HttpSession根本没意识到底层是Cookie在默默配合。2. 一张表看懂核心区别还有容易被忽略的细节2.1 主要差异对照我总结了下面这张表几乎覆盖了面试和实际开发中最常遇到的比较维度比较维度CookieSession存储位置浏览器端客户端服务器端内存/文件/Redis等数据容量单条约4KB单域名约20~50条各浏览器不同取决于存储介质理论上可存更多结构数据安全性明文字段可被用户查看和篡改数据在服务端用户不可直接读取生命周期受Expires/Max-Age控制可长时间有效默认随浏览器会话结束而失效可配置超时时间性能开销每次请求都会自动携带增加请求体大小占用服务端资源高并发下需要考虑存储策略跨域名行为可设置Domain属性实现一级域名下共享默认不跨域多服务间需自行设计同步方案典型应用场景记住登录状态、埋点统计、语言偏好等轻量数据用户登录态、购物车数据、权限信息等敏感状态不过我要提醒一句这张表看起来简单真正理解它需要把握住一个底层逻辑——谁保存数据谁就承担对应的安全责任和存储开销。Cookie把数据放在用户手里服务器只负责信任它那么风险自然在于用户能改Session把数据留在服务器风险就成了服务器存储瓶颈和分布式环境下的共享问题。所有的设计决策本质上都是在这两端之间找平衡。2.2 生命周期差异带来的实际问题生命周期这个问题我在项目里吃过亏。Cookie的过期时间完全由Expires或Max-Age决定你把过期时间设成30天用户只要在30天内再次请求Cookie就一直有效。Session则不同它的生命周期由服务器控制常见参数是inactiveInterval或timeout比如Tomcat默认的Session超时时间是30分钟超过30分钟没有请求服务器就会把Session销毁这时候即使用户浏览器里的JSESSIONID还是原来那个服务器也认不出来。曾经的踩坑经历是一个后台管理系统用户反馈隔一个中午回来就掉线。排查后发现运维在Nginx层面配置了proxy_read_timeout 300但后端的Session超时被Spring Security的默认策略控制成了1800秒两边配置不一致导致有请求时Session被重置、空闲久了却先被网络层切断用户侧表现就是“刚用得好好的过一会儿突然要重新登录”。后来我把Session超时时间、Nginx超时时间、前端轮询间隔统一梳理了一遍才彻底解决。2.3 用户无感知的“变体”没有Cookie时的URL重写与隐藏字段有一个细节很多人不知道如果浏览器禁用了CookieSession机制并不会直接失效。Servlet规范里有一种叫“URL重写URL Rewriting”的兜底方案——把Session ID拼接在URL后面形如/path/;jsessionidabc123服务器解析URL里的Session ID来找到对应会话。类似的还有一种做法是表单隐藏字段携带Session ID。听起来很美好但实际工作中我几乎不建议开启URL重写。原因有两个第一URL里带Session ID很容易被日志系统记录一旦日志泄露就等于会话被泄露第二用户把带Session ID的链接转发给别人对方就直接拿到了你的会话身份这是典型的重放攻击场景。所以我的观点是如果用户禁用了Cookie宁可引导他开启Cookie或者走无状态Token方案也不要为了兼容性引入URL重写这种低安全性设计。2.4 Cookie中文名、编码与网易这类大站的Cookie策略热词里有“cookie中文”和“网易cookie”这两个词其实折射出两个很实际的细节。先说中文值Cookie规范里规定Cookie的值不允许出现分号、逗号、空格等特殊字符而中文直接放进Cookie里在不同浏览器上的表现并不统一。正确的做法是用URLEncoder.encode()先做百分号编码读取时再URLDecoder.decode()解码。我在早期项目里曾经为了图省事直接把中文用户名塞进Cookie结果在Chrome下正常到了老版本Safari就出现乱码和请求异常排查了整整半天。再说中文域名和大厂的Cookie策略——网易这类门户网站你在www.163.com登录后访问mail.163.com、news.163.com这些子域时登录态是保持的靠的就是Domain属性。服务器下发Cookie时设置Domain.163.com所有163.com子域下的请求都会自动携带这个Cookie。这个机制在职级系统、企业门户这类多子域应用中非常常见。实现它的前提是各子域的应用共享同一套用户认证体系并且能够解析同一个Cookie中的凭证信息否则就会产生“域名下Cookie互通但业务互不认账”的尴尬局面。3. 核心区别背后的原理为什么要这样设计3.1 HTTP协议的无状态问题聊到为什么要区分Cookie和Session绕不开HTTP协议的根本约束——HTTP是无状态的。什么是无状态就是服务器默认不记得你是谁。第一次请求和第二次请求之间服务器层面没有任何关联。你第一次请求时往服务器存了个变量第二次想读取的时候服务器根本不知道这个变量属于谁。有人说“把用户数据存到全局变量里不就行了”那如果两个用户同时访问第三个用户就能看到前两个用户的数据这当然不行。于是需要一种机制让每次HTTP请求都能识别出“我是在继续之前那个对话”。Cookie和Session就是在这种需求下诞生的配套方案。3.2 客户端存储与服务端存储的实现选择既然要在无状态协议上建立会话状态单机场景下有两条路一是数据全放客户端二是数据留在服务端。Cookie走的第一条路Session走的第二条路。Cookie选择客户端存储的原因很好理解客户端存储能大幅降低服务端资源消耗无状态的服务器天然容易水平扩展。代价就是Cookie里的所有内容用户都看得到、改得了因此不能直接放敏感数据。Session选择服务端存储的原因是敏感数据不放服务端就等于把保险箱钥匙交到用户手里安全无从谈起。代价则是服务器要管理一份会随在线用户数增长而膨胀的数据。这两种思路后来演化出了更大的技术命题——如果你倾向于无状态、可扩展那就用Token方案JWT如果你倾向于可控、可吊销那就继续用Session。JWT本质上是把用户状态编码成一段签名数据存在客户端从存储位置上来说更接近Cookie的思路只是加密和签名机制增强了安全性。理解了Cookie和Session的设计取舍再去看JWT这类方案的优缺点就完全是降维打击了。3.3 安全边界的理解Cookie可篡改Session可伪造吗曾经有一个非常常见的误区“Session ID也在Cookie里那Session不也是能伪造吗”答案是Session ID本身是随机生成的重点是它能不能被预测。好的Session ID应该有足够的随机性和熵比如Java的SecureRandom、UUID等生成。只要Session ID不可预测伪造就没有意义——因为你猜不中。但这里有个衍生问题Session ID如果被偷了怎么办这就是经典的“会话固定攻击”和“会话劫持”问题。前者是攻击者在用户登录前塞给用户一个已知的Session ID等用户登录后这个ID还是同一个攻击者就用这个ID冒充用户后者是攻击者通过XSS或者其他手段拿到用户的Cookie直接借用别人的身份访问。这些问题不是Session机制本身有漏洞而是使用过程中没有做好安全防护。正确做法是登录成功后必须更换Session ID关键操作重新校验身份给Cookie打上HttpOnly和Secure标记。3.4 为什么有的项目用Cookie就够了有的一定要用Session我接过一个需求做一个纯展示类活动页用户选择语言偏好、浏览记录了一些筛选条件。这种数据不敏感、丢失也无所谓直接存Cookie就行。因为无状态、不占服务端资源还把后端的实现复杂度降到了最低。另一个需求是电商后台的商品发布系统用户一旦登录就能看到自己的店铺信息和草稿商品。这种数据必须放在Session或者服务端存储中因为第一敏感数据不能暴露在客户端第二服务端需要对这些数据做权限校验第三需要做到会话失效后立即无法访问而不是Cookie没过期就一直有效。选Cookie还是选Session核心标准其实是两条数据敏不敏感能不能允许用户控制过期时间。4. Java里的登录实战手写一个Cookie和Session协作的登录逻辑4.1 实现思路与目录结构这里我以一个典型的Java Servlet项目为例展示最原生的Cookie与Session协作流程。之所以不用Spring Boot是因为Spring封装得太彻底反而不利于理解底层机制。搞清楚原生原理后切到Spring Security或者Shiro都会轻松很多。先看一下简化版的目录结构src/main/java/com/demo/ ├── LoginServlet.java ├── LogoutServlet.java ├── HomeServlet.java └── AuthFilter.java核心思路用户提交用户名和密码后端校验成功后把用户信息写入Session同时下发一个记住登录状态的Cookie通常是加密后的用户名或一个持久化的Token后续请求通过Filter统一判断用户是否在线、Cookie是否有效。4.2 服务端校验与Session写入这是登录接口的核心逻辑WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); // 这里省略真实的数据库校验正常项目中应该从用户表查询并比对密码哈希 if (admin.equals(username) 123456.equals(password)) { // 登录成功创建Session写入用户信息 HttpSession session request.getSession(true); session.setAttribute(loginUser, username); // 设置Session过期时间单位是秒这里设置30分钟 session.setMaxInactiveInterval(30 * 60); // 判断是否勾选了“记住我” String rememberMe request.getParameter(rememberMe); if (on.equals(rememberMe)) { // 把用户名编码后写入Cookie注意实际项目要加密或使用随机Token不能明文 Cookie cookie new Cookie(rememberUser, URLEncoder.encode(username, UTF-8)); cookie.setMaxAge(7 * 24 * 60 * 60); // 7天 cookie.setHttpOnly(true); cookie.setPath(/); response.addCookie(cookie); } response.sendRedirect(/home); } else { response.getWriter().write(登录失败); } } }这里有几个细节必须强调第一session.setMaxInactiveInterval()设置的是空闲超时时间不是绝对过期时间。用户只要持续操作Session就不会过期一旦空闲超过30分钟服务器就会把它销毁。第二cookie.setHttpOnly(true)一定不能省略。不设置HttpOnlyJavaScript就能通过document.cookie读取Cookie值一旦页面存在XSS漏洞攻击者可以直接偷走用户凭证。第三示例里用用户名明文存Cookie是演示用真正的生产环境应该存一个随机的TokenToken和用户ID的映射关系存在缓存或数据库里。用户名是可以被遍历的明文存这个属于低水平安全漏洞。4.3 登录状态鉴权与自动登录有了登录接口还不够还需要一个过滤器统一判断用户是否已登录WebFilter(/*) public class AuthFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; // 1. 优先从Session中获取用户信息最安全数据在服务端 HttpSession session req.getSession(false); if (session ! null session.getAttribute(loginUser) ! null) { chain.doFilter(request, response); return; } // 2. Session中没有用户信息尝试从Cookie恢复登录态 Cookie[] cookies req.getCookies(); String rememberUser null; if (cookies ! null) { for (Cookie cookie : cookies) { if (rememberUser.equals(cookie.getName())) { rememberUser URLDecoder.decode(cookie.getValue(), UTF-8); break; } } } if (rememberUser ! null) { // 实际项目中这里要校验Token和数据库/缓存中的记录是否匹配 HttpSession newSession req.getSession(true); newSession.setAttribute(loginUser, rememberUser); chain.doFilter(request, response); return; } // 3. 未登录重定向到登录页 resp.sendRedirect(/login); } }这个Filter的逻辑用一句话概括就是Session优先Cookie兜底。Session能拿到就直接放行Session过期了才去翻CookieCookie匹配说明用户选择了“记住我”就重新建立Session。注意这里用req.getSession(false)而不是getSession(true)区别在于前者不会无故创建一个新Session能避免大量无意义的服务端Session创建——这个细节很值得养成习惯对内存占用有明显改善。4.4 退出登录时该清理什么退出登录最容易犯的错误是只清理Session不清理Cookie或者反过来。正确做法是两边都要清WebServlet(/logout) public class LogoutServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session request.getSession(false); if (session ! null) { session.invalidate(); // 销毁Session } // 清除“记住我”Cookie Cookie cookie new Cookie(rememberUser, null); cookie.setMaxAge(0); // 设置Max-Age为0立即删除 cookie.setPath(/); response.addCookie(cookie); response.sendRedirect(/login); } }setMaxAge(0)表示让浏览器立刻删除这个Cookie。如果把Max-Age设置为负数表示当浏览器关闭时删除效果会延迟到关闭浏览器才生效很多开发者在调试时遇到“退出后还在登录状态”的情况八成就是这个细节没处理好。清理Cookie时还需要注意Path属性必须和当初设置时保持一致否则delete命令不会生效——浏览器在匹配Cookie时是按域名加路径来定位的路径不一致就找不到要删的对象这是个很隐蔽的坑。4.5 从Java引申到PHP的Laravel Session配置热词里有“laravel session”这里也顺带提一下。Laravel的Session机制和Java思路相同但配置更灵活它支持file、cookie、database、redis、memcached、array等多种驱动。默认是file驱动Session数据存在storage/framework/sessions目录下。有一点要特别提醒Laravel里有个配置项叫secure如果开了secure env(SESSION_SECURE_COOKIE, false)浏览器只会在HTTPS连接下才会发送Session Cookie。生产环境如果没配HTTPS却把这个开关打开了用户会发现所有页面都处于“登录状态保持不了”的状态——因为每次请求的Cookie都不会被浏览器带上。这类问题往往出现在从HTTP迁移到HTTPS的过渡期排查时第一反应应该是去看这个开关。5. 安全测试工具视角Burp改Cookie和JMeter设置Cookie的实操5.1 为什么测试工具需要手动改Cookie日常开发联调时经常需要模拟一个已经登录的用户状态。最直接的办法就是拿一个合法用户的Cookie放进测试工具里发请求。工具层面的“改Cookie”本质上就是手动设置请求头中的Cookie字段。这种操作在接口测试、安全测试、性能测试里都很常见。这里特别需要说明合规前提以下操作仅限在你自己负责或有授权的测试环境中进行对他人系统进行未授权的Cookie篡改或会话攻击是违法行为。作为技术人员这一点要时刻清楚。5.2 Burp Suite修改Cookie的两步操作Burp Suite是Web安全测试里绕不开的抓包代理工具。用它改Cookie路径很简单第一步配置代理。打开Burp进入Proxy Options确认监听端口默认是8080。把浏览器流量代理到127.0.0.1:8080这时Burp就能拦截并查看所有HTTP请求。第二步拦截并修改。在Proxy Intercept页面打开拦截开关浏览器发起请求后Burp会暂停请求。在出现的Raw请求内容里找到Cookie那一行直接修改成你要测试的Cookie值然后点击Forward把修改后的请求放行。举例来说原Cookie是JSESSIONIDabc123你改成JSESSIONIDxyz789后请求就会以xyz789的身份发往后端。用Burp改Cookie最常见的两个测试场景一个是尝试篡改roleuser改成roleadmin用来验证后端有没有做服务端权限校验另一个是携带不存在的Session ID观察后端是否返回异常信息泄露。一个严谨的后端在权限和异常处理上都应该做得足够健壮——这恰好是Cookie与Session设计思路的一次实际验证。5.3 JMeter设置Cookie的四种方式JMeter做性能测试时模拟用户登录后的操作最关键的就是让同一个虚拟用户带同一个Cookie发请求。具体有四种方式我按推荐程度排序方式一使用HTTP Cookie管理器最简单、最推荐在线程组下添加“配置元件 HTTP Cookie管理器”。它复选框中有个“每次迭代清空Cookie”选项默认不勾选相当于自动保留当前线程迭代过程中收到的所有Cookie。你只需要在登录接口后面加一个接口Cookie管理器会自动把登录响应里的Set-Cookie带上。这种方式最接近真实浏览器行为。方式二手动添加Cookie在HTTP Cookie管理器面板中点击“添加”手动输入Cookie名和值比如NameJSESSIONID、Valuexxx。这种方式适合Cookie值固定不变的场景适合冒烟测试但对每个用户都不同ID的场景不适用。方式三使用HTTP头管理器添加“配置元件 HTTP头管理器”在Headers里手动加一行Cookie: JSESSIONIDxxx。这种方式会让该线程组下所有请求都带这个头不像Cookie管理器那样能自动响应服务器返回的Set-Cookie。手动控制效果最强但维护成本高。方式四通过BeanShell或JSR223脚本动态设置当Cookie值需要从上一个请求的响应中提取时用正则表达式提取器或JSON提取器从登录响应里取出Cookie存入变量${jsessionid}再配合HTTP头管理器使用Cookie: JSESSIONID${jsessionid}这种方式在压测中非常实用因为每个虚拟用户会登录并获得不同ID脚本再用各自的变量去发后续请求真正模拟了并发用户互相独立的场景。5.4 XSS攻击与Cookie保护HttpOnly的真实作用热词里有“xss攻击 cookie”这里一定要单独拿出来讲。XSS跨站脚本攻击的核心场景是攻击者把一段恶意JavaScript注入到页面中当其他用户访问这个页面时恶意脚本在用户的浏览器里执行脚本可以读取当前域名下的Cookie并发送到攻击者的服务器。HttpOnly属性就是专门针对这个场景的防御手段。设置了HttpOnly的Cookie浏览器会禁止JavaScript的document.cookie读取。攻击者就算注入脚本也拿不到那些被保护的Cookie。Cookie存储登录凭证时务必设置这个属性。这一条对于所有后端语言都一样Java的Cookie类可以直接调setHttpOnly(true)PHP的setcookie函数有httponly参数Python Flask的response.set_cookie也支持。但注意HttpOnly不是万能的。如果攻击者不发XSS而是直接在用户浏览器上做操作比如通过CSRF伪造请求那HttpOnly就起不到作用了。这也是为什么完整的安全方案从不只靠一个属性——需要Secure、SameSite、服务端校验、防CSRF Token等多个机制叠加。安全领域有个共识不要让单一防线承担全部安全责任纵深防御是唯一可靠策略。6. Session管理与高并发场景的升级方向6.1 Session存储的单机困境与Redis化实践单台服务器部署应用时Session默认存在内存里操作简单高效。但当应用变成多台服务器组成集群时问题就来了用户在服务器A上登录下次请求被负载均衡转发到了服务器B服务器B的内存里没有这份Session用户就变成了未登录状态。解决办法有三种配置负载均衡的粘性会话同一用户的请求固定转发到同一台服务器、Session同步复制在集群内广播同步Session数据、Session外部集中存储最常见的就是Redis。我用得最多的是第三种因为粘性会话会遇到单点故障问题同步复制在网络开销和内存占用上都很糟糕Redis方案则干净利落。Java里集成Redis Session的经典做法是用Spring Sessiondependency groupIdorg.springframework.session/groupId artifactIdspring-session-data-redis/artifactId /dependency引入依赖后只需加一个EnableRedisHttpSession注解容器就会自动把HttpSession的存取逻辑替换成Redis实现。Session数据以spring:session:sessions:{sessionId}为key存储在Redis里同时还有专门用于过期扫描的key集合。服务重启不影响已登录用户的会话集群节点共享同一份会话数据用户体验和运维效率都明显提升。6.2 Token化与无状态登录的演进逻辑做移动端App或者前后端完全分离的项目时Cookie和Session的组合会遇到天然障碍——App客户端没有浏览器那样的Cookie管理机制跨域请求处理Cookie也非常麻烦。这时候主流方案是采用Token认证常见实现是JWTJSON Web Token。JWT的思路是把用户身份和过期时间等信息编码进一段签名字符串服务端不保存会话状态每次请求来了验签即可。这套方案的好处是天然支持跨域、支持多端、服务器无状态容易扩容。缺点也同样明显一旦签发在过期时间到达之前无法主动吊销如果密钥泄露所有Token都会被伪造Token里不能存太多数据否则请求头会变得很大。所以我参与过的项目里往往不是简单的二选一。传统Web管理后台用Session Cookie因为可以主动踢人、会话控制更强对外API服务用JWT因为无状态、多端扩展方便两者在一个系统里共存也不奇怪。技术选型永远是场景驱动的不掌握本质差异照搬任何方案都容易踩坑。6.3 常见问题与排查技巧速查表最后把我这些年积累的会话问题排查经验整理成一张速查表遇到类似问题可以直接对照现象可能原因排查步骤解决方案登录后立刻掉线Cookie的Domain/Path不匹配用浏览器开发者工具Network面板查看请求和响应中的Set-Cookie与请求Cookie统一设置Path/Domain留空或使用一级域名刷新后偶发掉线集群多节点Session不一致查看负载均衡是否开启了粘性会话检查Session存储模式引入Redis共享Session或开启粘性会话退出登录后还能访问受保护页面没清Cookie或Cookie的Path不一致对比设置Cookie和删除Cookie时的Path是否一致删除Cookie时保持Path与设置时一致手机端和PC端登录状态互相干扰Cookie作用域设置过大检查是否把Domain设置成了顶级域名按业务拆分域名或限制Path范围Cookie里存中文乱码没有进行URL编码查看原始Cookie值的编码方式统一使用URLEncoder/URLDecoder处理Session内存持续增长没设置Timeout或单用户Session过大用jstat或VisualVM查看内存占用设置合理的MaxInactiveInterval避免Session存入大对象HTTPS网站Cookie丢失设置Cookie时没有加Secure或反向代理没传HTTPS头抓包看请求和响应协议是否一致Cookie加Secure属性Nginx配置proxy_set_header X-Forwarded-Proto并发用户多时响应变慢Session存储成为瓶颈监控Redis慢查询或数据库连接数Session数据迁移到Redis开启连接池优化排查这类问题时我最常用的工具组合是Chrome开发者工具看Cookie收发、Nginx访问日志看请求转发路径、redis-cli监控Session key的变化。三件套组合起来绝大多数会话问题都能在半小时内定位到根因。Cookie和Session看起来只是两个基础概念但它们在Web应用中的覆盖面极广——从一次简单登录到跨域单点登录从单机部署到千台集群处处都有它们的身影。我在实际项目中最大的体会是不要在项目启动时才去想Session怎么存、Cookie怎么设而是在架构设计阶段就把这两者的关系想透。你是偏无状态的API服务还是偏传统的Web应用用户的敏感数据最终落在哪里谁来控制会话的有效期这三个问题想清楚了Cookie和Session的使用方案自然就出来了。如果这篇能帮你在这些问题上多一层理解技术路上的很多弯路就都能少走一些。
返回列表