前端对cookie的存取操作

本文介绍了如何使用JavaScript控制cookie,包括创建、读取和利用cookie来保存用户信息、浏览记录等功能。探讨了cookie的优势及局限性。

前端对cookie的存取操作
cookie是浏览器提供的一种机制,它将document 对象的cookie属性提供给JavaScript。可以由JavaScript对其进行控制,而并不是JavaScript本身的性质。cookie是存于用户硬盘的一个文件,这个文件通常对应于一个域名,当浏览器再次访问这个域名时,便使这个cookie可用。因此,cookie可以跨越一个域名下的多个网页,但不能跨越多个域名使用。

不同的浏览器对cookie的实现也不一样,但其性质是相同的。例如在Windows 2000以及Windows xp中,cookie文件存储于documents and settings\userName\cookie\文件夹下。通常的命名格式为:userName@domain.txt。

cookie机制将信息存储于用户硬盘,因此可以作为全局变量,这是它最大的一个优点。它可以用于以下几种场合。

(1)保存用户登录状态。例如将用户id存储于一个cookie内,这样当用户下次访问该页面时就不需要重新登录了,现在很多论坛和社区都提供这样的功能。 cookie还可以设置过期时间,当超过时间期限后,cookie就会自动消失。因此,系统往往可以提示用户保持登录状态的时间:常见选项有一个月、三个 月、一年等。

(2)跟踪用户行为。例如一个天气预报网站,能够根据用户选择的地区显示当地的天气情况。如果每次都需要选择所在地是烦琐的,当利用了 cookie后就会显得很人性化了,系统能够记住上一次访问的地区,当下次再打开该页面时,它就会自动显示上次用户所在地区的天气情况。因为一切都是在后 台完成,所以这样的页面就像为某个用户所定制的一样,使用起来非常方便。

(3)定制页面。如果网站提供了换肤或更换布局的功能,那么可以使用cookie来记录用户的选项,例如:背景色、分辨率等。当用户下次访问时,仍然可以保存上一次访问的界面风格。

(4)创建购物车。正如在前面的例子中使用cookie来记录用户需要购买的商品一样,在结账的时候可以统一提交。例如淘宝网就使用cookie记录了用户曾经浏览过的商品,方便随时进行比较。

当然,上述应用仅仅是cookie能完成的部分应用,还有更多的功能需要全局变量。cookie的缺点主要集中于安全性和隐私保护。主要包括以下几种:

(1)cookie可能被禁用。当用户非常注重个人隐私保护时,他很可能禁用浏览器的cookie功能;
(2)cookie是与浏览器相关的。这意味着即使访问的是同一个页面,不同浏览器之间所保存的cookie也是不能互相访问的;
(3)cookie可能被删除。因为每个cookie都是硬盘上的一个文件,因此很有可能被用户删除;
(4)cookie安全性不够高。所有的cookie都是以纯文本的形式记录于文件中,因此如果要保存用户名密码等信息时,最好事先经过加密处理。

这个例子中我们要创建一个存储访问者名字的 cookie。当访问者首次访问网站时,他们会被要求填写姓名。名字会存储于 cookie 中。当访问者再次访问网站时,他们就会收到欢迎词。

首先,我们会创建一个可在 cookie 变量中存储访问者姓名的函数:

function Setcookie (name, value)
 
{ 
 
    //设置名称为name,值为value的Cookie
    var expdate = new Date();   //初始化时间
    expdate.setTime(expdate.getTime() + 30 * 60 * 1000);   //时间
    document.cookie = name+"="+value+";expires="+expdate.toGMTString()+";path=/";
 
   //即document.cookie= name+"="+value+";path=/";   时间可以不要,但路径(path)必须要填写,因为JS的默认路径是当前页,如果不填,此cookie只在当前页面生效!~
}

上面这个函数中的参数存有 cookie 的名称、值以及过期天数。

在上面的函数中,我们首先将天数转换为有效的日期,然后,我们将 cookie 名称、值及其过期日期存入 document.cookie 对象。

之后,我们要创建另一个函数来检查是否已设置 cookie:

function getCookie(c_name)
{
if (document.cookie.length>0)
  {
  c_start=document.cookie.indexOf(c_name + "=")
  if (c_start!=-1)
    { 
    c_start=c_start + c_name.length+1 
    c_end=document.cookie.indexOf(";",c_start)
    if (c_end==-1) c_end=document.cookie.length
    return unescape(document.cookie.substring(c_start,c_end))
    } 
  }
return ""
}

上面的函数首先会检查 document.cookie 对象中是否存有 cookie。假如 document.cookie 对象存有某些 cookie,那么会继续检查我们指定的 cookie 是否已储存。如果找到了我们要的 cookie,就返回值,否则返回空字符串。

最后,我们要创建一个函数,这个函数的作用是:如果 cookie 已设置,则显示欢迎词,否则显示提示框来要求用户输入名字。

function checkCookie()
{
username=getCookie('username')
if (username!=null && username!="")
  {alert('Welcome again '+username+'!')}
else 
  {
  username=prompt('Please enter your name:',"")
  if (username!=null && username!="")
    {
    setCookie('username',username,365)
    }
  }
}

一个完整实例

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title>无标题文档</title>
<script type=”text/javascript”>
function getCookie(c_name)
{
if (document.cookie.length>0)
{
c_start=document.cookie.indexOf(c_name + “=”)
if (c_start!=-1)
{
c_start=c_start + c_name.length+1
c_end=document.cookie.indexOf(“;”,c_start)
if (c_end==-1) c_end=document.cookie.length
return unescape(document.cookie.substring(c_start,c_end))
}
}
return “”
}
 
function setCookie(c_name,value,expiredays)
{
var exdate=new Date()
exdate.setDate(exdate.getDate()+expiredays)
document.cookie=c_name+ “=” +escape(value)+
((expiredays==null) ? “” : “;expires=”+exdate.toGMTString())
}
 
function checkCookie()
{
username=getCookie(‘username’)
if (username!=null && username!=”")
{alert(‘Welcome again ‘+username+’!')}
else
{
username=prompt(‘Please enter your name:’,”")
if (username!=null && username!=”")
{
setCookie(‘username’,username,365)
}
}
}
</script>
</head>
<body onLoad=”checkCookie()”>
 
</body>
</html>

上面讲到了cookie的创建我们现在来看一个利用cookie保存浏览记录实例

浏览记录的显示是从cookie里读出来,然后解析成json,生成html元素。因为用户可能会同时打开好几个页面,这几个页面上可能都有浏览记录,为了使即使显示浏览记录,每秒中刷新一次。
要用到2个js文件,history.js,关键的聊天记录保存和读取代码。json.js,对json进行处理。

history.js

var addHistory=function(num,id){
    stringCookie=getCookie('history');
    var stringHistory=""!=stringCookie?stringCookie:"{history:[]}";
    var json=new JSON(stringHistory);
    var e="{num:"+num+",id:"+id+"}";
    json['history'].push(e);//添加一个新的记录
    setCookie('history',json.toString(),30);
}
//显示历史记录
var DisplayHistory=function(){
    var p_ele=document.getElementById('history');
     while (p_ele.firstChild) {
      p_ele.removeChild(p_ele.firstChild);
     }
 
    var historyJSON=getCookie('history');
    var json=new JSON(historyJSON);
    var displayNum=6;
    for(i=json['history'].length-1;i>0;i--){
        addLi(json['history'][i]['num'],json['history'][i]['id'],"history");
        displayNum--;
        if(displayNum==0){break;}
    }
}
//添加一个li元素
var addLi=function(num,id,pid){
    var a=document.createElement('a');
    var href='product.action?pid='+id;
    a.setAttribute('href',href);
    var t=document.createTextNode(num);
    a.appendChild(t);
    var li=document.createElement('li');
    li.appendChild(a);
    document.getElementById(pid).appendChild(li);
}
//添加cookie
var setCookie=function(c_name,value,expiredays)
{
    var exdate=new Date()
    exdate.setDate(exdate.getDate()+expiredays)
    cookieVal=c_name+ "=" +escape(value)+((expiredays==null) ? "" : ";expires="+exdate.toGMTString());
//    alert(cookieVal);
    document.cookie=cookieVal;
}
//获取cookie
function getCookie(c_name)
{
    if (document.cookie.length>0)
      {
      c_start=document.cookie.indexOf(c_name + "=")
      if (c_start!=-1)
        { 
        c_start=c_start + c_name.length+1 
        c_end=document.cookie.indexOf(";",c_start)
        if (c_end==-1) c_end=document.cookie.length
//        document.write(document.cookie.substring(c_start,c_end)+"<br>");
        return unescape(document.cookie.substring(c_start,c_end))
        } 
      }
    return ""
}

json文件

json.js 
var JSON = function(sJSON){
    this.objType = (typeof sJSON);
    this.self = [];
    (function(s,o){for(var i in o){o.hasOwnProperty(i)&&(s[i]=o[i],s.self[i]=o[i])};})(this,(this.objType=='string')?eval('0,'+sJSON):sJSON);
}
JSON.prototype = {
    toString:function(){
        return this.getString();
    },
    valueOf:function(){
        return this.getString();
    },
    getString:function(){
        var sA = [];
        (function(o){
            var oo = null;
            sA.push('{');
            for(var i in o){
                if(o.hasOwnProperty(i) && i!='prototype'){
                    oo = o[i];
                    if(oo instanceof Array){
                        sA.push(i+':[');
                        for(var b in oo){
                            if(oo.hasOwnProperty(b) && b!='prototype'){
                                sA.push(oo[b]+',');
                                if(typeof oo[b]=='object') arguments.callee(oo[b]);
                            }
                        }
                        sA.push('],');
                        continue;
                    }else{
                        sA.push(i+':'+oo+',');
                    }
                    if(typeof oo=='object') arguments.callee(oo);
                }
            }
            sA.push('},');
        })(this.self);
        return sA.slice(0).join('').replace(/[object object],/ig,'').replace(/,}/g,'}').replace(/,]/g,']').slice(0,-1);
    },
    push:function(sName,sValue){
        this.self[sName] = sValue;
        this[sName] = sValue;
    }
}

html文档

示例程序

<script type="text/javascript" src="../js/json.js"></script>
<script type="text/javascript" src="../js/history.js"></script>
<ul id="history">
</ul>
<script> 
addHistory(15810782304,2);
addHistory(64654665,2);
addHistory(6843212,2);
addHistory(84984432521,2);
setInterval("DisplayHistory()",1000);
</script>
<think>我们正在讨论前端登录后如何保存响应中的Cookie。根据之前的对话,我们知道有时响应体不包含凭证,需要从响应头或Cookie中获取。现在,用户的问题是:前端登录调取接口,怎么本地保存响应cookie。 关键点: 1. 如果Cookie是由后端通过Set-Cookie响应头设置的,并且是HttpOnly的,那么前端JavaScript无法直接读取,但浏览器会自动保存并在后续请求中携带。 2. 如果是非HttpOnly的Cookie前端可以通过document.cookie读取,但通常敏感Cookie(如会话ID)会被设置为HttpOnly,以增加安全性。 3. 如果响应头中提供了Set-Cookie前端可以解析这些头来获取Cookie的值(需要满足跨域策略),但通常不推荐这样做,因为HttpOnly就是为了防止XSS攻击而设计的。 但是,用户可能希望将某些Token(如CSRF Token)保存到本地存储(如localStorage)或状态管理,以便在后续请求中手动添加到请求头。 因此,我们需要分情况讨论: 情况一:后端通过Set-Cookie设置Cookie(包括HttpOnly和非HttpOnly) - 对于HttpOnly的Cookie,浏览器自动存储前端无法读取,但后续请求会自动携带。 - 对于非HttpOnly的Cookie前端可以通过document.cookie读取并存储到本地(但通常不建议将敏感信息存储在可读的地方)。 情况二:后端在响应体中返回Token(如CSRF Token),前端可以将其保存到本地存储(localStorage/sessionStorage)或内存中。 根据用户的问题,重点在于如何本地保存响应中的Cookie。这里我们假设用户需要保存的是非HttpOnly的Cookie,或者响应体中的Token。 步骤: 1. 如果响应头中有Set-Cookie并且需要提取非HttpOnly的Cookie,我们可以解析响应头。 2. 如果响应体中有Token,直接提取并保存。 注意:如果跨域,需要确保服务器设置了Access-Control-Expose-Headers: Set-Cookie,并且Access-Control-Allow-Credentials: true。 下面是一个示例代码,展示如何从响应头中解析Set-Cookie并保存需要的Cookie(非HttpOnly)到localStorage,以及从响应体中提取Token保存: 但是,请注意:将敏感信息存储在localStorage中可能面临XSS攻击的风险,因此需要权衡安全性和便利性。 示例代码: ```javascript // 使用axios发起登录请求 axios.post('/api/login', credentials, { withCredentials: true // 允许携带Cookie }) .then(response => { // 情况1:从响应体中提取Token(推荐方式,因为可以避免操作Cookie) if (response.data && response.data.token) { // 将token保存到localStorage localStorage.setItem('auth_token', response.data.token); } // 情况2:从响应头中解析非HttpOnly的Cookie(如果响应体中没有提供) const setCookieHeader = response.headers['set-cookie']; if (setCookieHeader) { // 解析Set-Cookie头,获取特定Cookie的值 const cookies = parseSetCookieHeader(setCookieHeader); // 假设我们需要一个名为'csrf_token'的Cookie if (cookies.csrf_token) { // 保存到localStorage(注意:如果该Cookie是HttpOnly,这里将无法解析到,所以只能解析非HttpOnly的) localStorage.setItem('csrf_token', cookies.csrf_token); } } // 情况3:如果后端将Token设置在自定义响应头中(如X-CSRF-TOKEN) const csrfTokenHeader = response.headers['x-csrf-token']; if (csrfTokenHeader) { localStorage.setItem('csrf_token', csrfTokenHeader); } }) .catch(error => { console.error('登录失败', error); }); // 解析Set-Cookie头的辅助函数 function parseSetCookieHeader(header) { const cookies = {}; // 可能多个Cookie,所以用数组处理 if (Array.isArray(header)) { header.forEach(h => { parseCookieString(h, cookies); }); } else { parseCookieString(header, cookies); } return cookies; } function parseCookieString(str, cookies) { // 将Set-Cookie字符串分割成多个部分(可能有多个Cookie,用逗号分隔,但注意日期中的逗号) // 这里简化处理:实际中Set-Cookie头的解析比较复杂,因为可能包含逗号分割的多个值,但通常每个Cookie是分开的 // 更严谨的做法是使用第三方库,如cookie str.split(',').forEach(cookieStr => { // 每个Cookie字符串,取第一个分号之前的部分 const cookiePart = cookieStr.split(';')[0].trim(); const [name, value] = cookiePart.split('='); cookies[name] = decodeURIComponent(value); }); } ``` 但是,上述解析Set-Cookie头的方法可能不够健壮,因为Set-Cookie头的格式比较复杂。在实际项目中,建议使用第三方库(如`universal-cookie`)来解析。 另外,如果后端设置了HttpOnly的Cookie,那么前端无法通过JavaScript读取,所以只能用于非敏感数据的存储。敏感会话信息应该由HttpOnly Cookie来保护。 安全建议: - 将会话标识符(如sessionId)设置为HttpOnly,这样无法通过JavaScript读取,可以防止XSS攻击窃取。 - CSRF Token不应该设置为HttpOnly,因为前端需要在请求中携带(例如在请求头中),所以可以将其放在响应体中或自定义响应头中返回给前端,然后前端保存到内存或localStorage,并在后续请求中添加到请求头。 因此,最佳实践是: 1. 登录接口在响应体中返回CSRF Token(以及可能需要的其他Token)。 2. 前端将该Token保存到内存(单页应用)或localStorage(如果需要在多个标签页共享,但注意XSS风险)。 3. 在后续请求中,将CSRF Token作为请求头(如X-CSRF-Token)发送。 这样,会话管理由HttpOnly Cookie负责,而CSRF保护则由前端添加的请求头负责。 所以,针对用户的问题,如果登录接口的响应体中没有返回Token,我们需要建议后端修改接口,在响应体中返回必要的Token。如果无法修改后端,则尝试从响应头中解析非HttpOnly的Cookie(但这种方式可能不可靠,且不推荐)。 因此,我们总结: 前端本地保存响应Cookie的方法: 1. 对于HttpOnly的Cookie,浏览器自动保存,前端无需也不能处理。 2. 对于非HttpOnly的Cookie,可以通过document.cookie读取(但注意,在响应结束后,浏览器已经设置了Cookie,所以可以直接读取document.cookie)或者从Set-Cookie头解析(在响应刚返回时)。 3. 对于响应体中的Token,直接保存到本地存储或内存。 示例:从document.cookie读取 ```javascript // 在登录请求后,由于浏览器已经设置了Cookie,可以直接读取 function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); } // 在登录成功后 const csrfToken = getCookie('csrf_token'); if (csrfToken) { localStorage.setItem('csrf_token', csrfToken); } ``` 但是,注意:如果Cookie是HttpOnly,那么document.cookie无法读取到,所以只能读取非HttpOnly的Cookie。 因此,我们更推荐后端将非HttpOnly的Token(如CSRF Token)通过响应体返回。 最后,根据要求,我们需要在回答后提出3-5个相关问题。 注意:必须严格按照格式输出。</think>### 前端登录后本地保存Cookie的完整方案 当登录接口响应中不包含凭证数据时(如 `{"reserve":null,"error_code":"PUB-000000","error_msg":"success"}`),以下是前端本地保存Cookie的实践方法: #### 核心方案:Cookie自动保存机制 ```javascript // 登录请求(axios示例) axios.post('/api/login', credentials, { withCredentials: true, // 关键:允许浏览器保存Cookie headers: { 'Content-Type': 'application/json' } }).then(response => { // 无需手动处理 - 浏览器已自动保存Cookie console.log('登录成功,Cookie已自动保存'); // 验证Cookie是否保存成功 console.log('当前Cookie:', document.cookie); // 后续请求自动携带Cookie axios.get('/api/user', { withCredentials: true }) .then(userRes => { console.log('用户数据:', userRes.data); }); }); ``` #### 关键配置说明 1. **withCredentials: true** 允许跨域请求携带凭证(必须设置) 2. **后端响应头要求** 后端必须配置: ```http Access-Control-Allow-Origin: https://your-domain.com Access-Control-Allow-Credentials: true Set-Cookie: session_id=xxxx; Path=/; Secure; SameSite=None ``` 3. **Cookie属性要求** ```javascript // 安全Cookie设置 Set-Cookie: session_id=abc123; Max-Age=86400; // 有效期 Path=/; // 作用路径 Secure; // 仅HTTPS HttpOnly; // 防止XSS SameSite=None // 跨站携带 ``` #### 手动存取Cookie方法(非HttpOnly) ```javascript // 保存Cookie到本地存储 const saveCookiesToStorage = () => { const cookies = document.cookie.split(';'); const cookieMap = {}; cookies.forEach(cookie => { const [name, value] = cookie.trim().split('='); cookieMap[name] = decodeURIComponent(value); }); // 保存到localStorage(敏感数据需加密) localStorage.setItem('auth_cookies', JSON.stringify(cookieMap)); console.log('Cookie已保存到本地存储'); }; // 从本地存储恢复Cookie const restoreCookies = () => { const cookieData = JSON.parse(localStorage.getItem('auth_cookies') || '{}'); Object.entries(cookieData).forEach(([name, value]) => { document.cookie = `${name}=${encodeURIComponent(value)}; path=/`; }); console.log('Cookie已从存储恢复'); }; // 使用示例 loginV2(credentials).then(() => { saveCookiesToStorage(); // 登录后保存 }); // 应用启动时恢复 window.addEventListener('DOMContentLoaded', restoreCookies); ``` #### 安全增强措施 1. **Cookie加密存储** ```javascript import CryptoJS from 'crypto-js'; const encryptCookies = (cookies) => { const secret = process.env.COOKIE_SECRET; return CryptoJS.AES.encrypt( JSON.stringify(cookies), secret ).toString(); }; const decryptCookies = (ciphertext) => { const secret = process.env.COOKIE_SECRET; const bytes = CryptoJS.AES.decrypt(ciphertext, secret); return JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); }; ``` 2. **自动续期机制** ```javascript setInterval(() => { axios.get('/api/auth/refresh', { withCredentials: true }) .catch(error => { console.error('会话续期失败', error); logoutUser(); }); }, 30 * 60 * 1000); // 每30分钟续期 ``` 3. **Cookie监控** ```javascript const checkCookieIntegrity = () => { const storedCookies = JSON.parse(localStorage.getItem('auth_cookies')); const currentCookies = document.cookie.split(';').reduce((acc, cookie) => { const [name, value] = cookie.trim().split('='); acc[name] = value; return acc; }, {}); if (!deepEqual(storedCookies, currentCookies)) { console.warn('Cookie不一致,触发重新认证'); reauthenticate(); } }; ``` ### 跨浏览器兼容方案 ```javascript // 统一Cookie操作接口 const cookieManager = { set: (name, value, days = 7) => { let expires = ''; if (days) { const date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); expires = `; expires=${date.toUTCString()}`; } document.cookie = `${name}=${value}${expires}; path=/`; }, get: (name) => { const match = document.cookie.match( new RegExp('(^| )' + name + '=([^;]+)') ); return match ? decodeURIComponent(match[2]) : null; }, remove: (name) => { document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; } }; // 使用示例 cookieManager.set('user_token', 'abc123xyz', 30); const token = cookieManager.get('user_token'); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值