前后端分开开发时,我们的前端请求是跨域请求,会导致session和cookie失效。看了各种方案,我选择使用redis来实现session的方案,保证前端使用跨域请求时,后端能够保持用户session。为什么选择redis来实现跨域会话?看了各种跨域session丢失的解决方案,但是都没有效果,所以最终还是选择了redis来解决这个问题。前后端添加凭证后,浏览器无法自动加载第三方cookie,服务器上的session和cookie依然丢失。前端Fetch跨域请求constdata={key:"value"};//参数constmyHeaders=newHeaders();myHeaders.append('Access-Control-Allow-Origin','http://localhost:3000/');//设置Access-Control-Allow-Credentials,跨域请求需要授权myHeaders.append('Access-Control-Allow-Credentials','true');//设置mode为cors,进行跨域请求myHeaders.append('mode','cors');//设置Content-Type,参数格式myHeaders.append('Content-Type','application/x-www-form-urlencoded')varurlencoded=newURLSearchParams()for(letkeyindata){urlencoded.append(key,data[key])}constrequestOptions={method:'POST',headers:myHeaders,body:urlencoded,redirect:'follow',//设置为include以确保为跨域请求保留cookie凭据:'include',}fetch(api,requestOptions).then(response=>response.json());egg跨域配置//config.default.js'usestrict'constpath=require('path')module.exports=appInfo=>{constconfig={mode:'file',errorHandler:{match:'/'},}//套security中的csrf关闭,允许跨域请求config.security={domainWhiteList:['*'],csrf:{enable:false}}//设置cors插件配置,origin为前端源(withcredentialscannotbesetto*)//设置credentials为true,返回的Header中Access-Control-Allow-Credentials为trueconfig.cors={origin:'http://localhost:3000',credentials:true,allowMethods:'GET,HEAD,PUT,POST,DELETE,PATCH'}//这里设置彩蛋自带的session,但是跨域请求还是会丢失sessionconfig.session={key:'WheelFit',maxAge:30*24*3600*1000,//30天httpOnly:true,encrypt:true,renew:true}//自定义中间件,sessionToken为认证中间件,收到请求config后获取session中存储的token。middleware=['sessionToken','errorHandler']return{...config,}}//plugin.js'usestrict';//添加cors插件回复跨域请求//npmi--saveegg-corsmodule.exports={cors:{enable:true,package:'egg-cors',}};这个配置是在其他解决跨域会话丢失问题的文章中找到的。理论上,添加凭证可以保持session,但是这里不生效。跨域请求仍然会丢失会话,并且为响应设置的cookie浏览器无法获取,但是使用postman发送非跨域请求可以记录session。无奈只能选择使用redis维护跨域请求的sessionRedis配置。前端Fetch请求保持不变(虽然不再需要设置credential)后端需要添加新的egg-redis插件//plugin.js'usestrict';//添加cors插件回复跨域请求//npmi--saveegg-cors//npmi--saveegg-redismodule.exports={cors:{enable:true,package:'egg-cors',},redis:{enable:true,package:'egg-redis',},};//config.default.jsconfig.redis={client:{port:6379,//Redis端口host:'127.0.0.1',//Redis主机密码:'',db:0}}使用redis设置值//login.jsasynclogin(){const{ctx}=this;//登录操作//登录成功consttoken=generateToken();CTX。app.redis.set(`token${userid}`,token);return(ctx.body={success:true,userid:userid})}//检查sessionasyncsession_token(){const{ctx}=this;const{userid,token}=ctx.request.body;constredis_token=ctx.app.redis.get(`token${userid}`);如果(redis_token===token){return(ctx.body={success:true});}返回(ctx.body={success:false});}这样我们在服务端使用redis来设置跨域请求的缓存状态,也可以设置定时任务来删除状态
