前言
谷歌80新加了一个SameSite属性,防止跨域。但是就是由于这个新加的属性,我无法把cookie传到前端,搜罗了全网找到了两种解决方法,在此记录一下。
如果console出现下面这个,那cookie估计就没设置上:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902150618729.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NzY0NDc3,size_16,color_FFFFFF,t_70#pic_center)
A cookie associated with a cross-site resource at http://stu.hrbkyd.com/ was set without the SameSite
attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with SameSite=None
and Secure
. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.
先看一下能正常设置cookie的request和response
addCookie的response:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902142856843.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NzY0NDc3,size_16,color_FFFFFF,t_70#pic_center)
getCookie的request:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902142925158.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NzY0NDc3,size_16,color_FFFFFF,t_70#pic_center)
可以看出添加cookie的response会有 Set-Cookie 字段,getCookie的request会有 Cookie 字段,有这两个字段才能添加成功。
下面来看springboot下的操作。
方法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @GetMapping("/addCookie3") @ResponseBody public String addCookie3(@RequestParam("name") String name,@RequestParam("value") String value,HttpServletRequest request,HttpServletResponse response) { System.out.println(name+" "+value); Cookie cookie = new Cookie(name,value); cookie.setDomain(domain); cookie.setHttpOnly(false); cookie.setPath(request.getContextPath()); cookie.setMaxAge(60*60*24); response.addCookie(cookie); String s = name+"="+value+";"; response.setHeader("Set-Cookie",s + "Path=*; SameSite=None; Secure"); return "success"; } @GetMapping("/getCookie") @ResponseBody public String getCookie(@RequestParam("name") String name,HttpServletRequest request) { Cookie[] cookies = request.getCookies(); if (cookies == null) { return "no cookies"; } for (Cookie cookie : cookies) { System.out.println(cookie.getName()+" "+cookie.getValue()); } for (Cookie cookie : cookies) { if (cookie.getName().equals(name)) { return cookie.getValue(); } } return "no such cookie"; }
|
效果图:
说明:测试用页面的两个set按钮分别是添加cookie,一个为添加demoData=demoData,另一个为demoData2=damoData2,两个get是没别获取demoData和demoData2.
添加demoData:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902144237887.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NzY0NDc3,size_16,color_FFFFFF,t_70#pic_center)
可以看出response的Set-Cookie字段存在值。这里我的SameSite设置为了None,这样就必须再设置一个属性Secure,并且用https连接,这里是迫不得已,还可以设置为SameSite=Lax,这样就不用设置Secure,但是这样我无法get到值,所以采用None搭配Secure。
得到demoData:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902144637832.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NzY0NDc3,size_16,color_FFFFFF,t_70#pic_center)
本次我们发送的request也存在之前设置的cookie,并且也取到了值。
如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902144824228.PNG#pic_center)
现在我们添加了一个cookie是成功了,这时我就在想,上面的代码是拼接的Set-Cookie字段,那么设置下一个cookie时要不要把之前的cookie也获取到,然后再拼接上新cookie呢?
比如说在设置一个demoData2=demoData2,那么这次用不用写成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 其实是不用的。这里在测试一下就可以,我们点击第二个set按钮,看看发生什么。 #### 添加demoData2 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902145320718.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NzY0NDc3,size_16,color_FFFFFF,t_70#pic_center) 可以看出,request发送时候带有demoData=demoData,response我们并没有像上面那么拼接,只拼接了demoData2,但是response自动带上了demoData。 #### 得到demoData2 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902145515862.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NzY0NDc3,size_16,color_FFFFFF,t_70#pic_center) 全部结果如下 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902145601864.PNG#pic_center) 成功的取到了demoData2. 下面来看方法二 ### 方法二 get方法是一样的,这里只贴出来addCookie ```java @GetMapping("/addCookie2") @ResponseBody public String addCookie2(@RequestParam("name") String name,@RequestParam("value") String value,HttpServletRequest request,HttpServletResponse response) { System.out.println(name+" "+value); //new HttpCookie cookie = CookieUtils.generateSetCookie(request, name, value,Duration.ofHours(24 * 7));//七天过期 response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString()); return "success"; }
|
下面是CookieUtils
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class CookieUtils { private final static String domain = "xxx.com"; public static HttpCookie generateSetCookie(HttpServletRequest request, String name, String value,Duration duration){ ResponseCookie cookie = ResponseCookie.from(name, value) .secure(true) .domain(domain) .path("*") .maxAge(duration) .sameSite("None") .build() ; return cookie; } }
|
具体情况和细节与方法一是一样的。
deleteCookie
有了添加的方法,删除就不难了,只需要把有效时间变为0就行。下面采用方法2来删除cookie。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @GetMapping("/deleteCookie") @ResponseBody public String deleteCookie(String names, HttpServletRequest request,HttpServletResponse response) { System.out.println("names:"+names); Cookie[] cookies = request.getCookies(); if (cookies == null) { return "no cookies"; } for (int i = 0; i < cookies.length; i++) { if (names.equals(cookies[i].getValue())) { ResponseCookie cookie = (ResponseCookie)CookieUtils.generateSetCookie(request,names,null,Duration.ZERO); response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString()); break; } } return "success"; }
|
设置session
cookie整明白了,session就好设置了,因为session是通过Set-Cookie的JSESSIONID设置的,只需要获取到JSESSIONID就行。
1 2 3 4 5 6 7 8 9 10 11 12
| @GetMapping("/setSession") @ResponseBody public Result setSession(String str,HttpSession session,HttpServletRequest request,HttpServletResponse response) { System.out.println(str); session.setAttribute("str",str); String id = session.getId(); HttpCookie cookie = CookieUtils.generateSetCookie(request, "JSESSIONID", id, Duration.ofHours(3)); response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString()); Result result = new Result(); result.setCode(HttpStatus.OK.value()); return result; }
|
最后附上测试用前端代码
注意如果设置SameSite=None,必须设置Secure,并且用https传输。如果是SameSite=Lax,则没有前面要求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.20.0-0/axios.js"></script> <script src="https: </head> <body> <button id="btn1">按钮1(set)</button> <button id="btn2">按钮2(get)</button> <button id="btn3">按钮3(set)</button> <button id="btn6">按钮6(get)</button> <button id="btn4">按钮4(delete1)</button> <button id="btn5">按钮4(delete2)</button> <script>
let config = {headers: {'Content-Type': 'application/x-www-form-urlencoded'}}; let domain = "localhost" $(function () { axios.defaults.withCredentials = true; $("#btn1").click(function () { axios.get('https://xxx.com/test/addCookie?name=demoData&value=demoData').then(res => { console.log(res.data); }); });
$("#btn2").click(function () { axios.get('https://xxx.com/test/getCookie?name=demoData').then(res => { console.log(res.data); }); })
$("#btn3").click(function () { axios.get('https://xxx.com/test/addCookie?name=demoData2&value=demoData2').then(res => { console.log(res.data); }); });
$("#btn4").click(function () { axios.get('https://xxx.com/test/deleteCookie?names=demoData').then(res => { console.log(res.data); }); });
$("#btn5").click(function () { axios.get('https://xxx.com/test/deleteCookie?names=demoData2').then(res => { console.log(res.data); }); });
$("#btn6").click(function () { axios.get('https://xxx.com/test/getCookie?name=demoData2').then(res => { console.log(res.data); }); }) })
</script> </body> </html>
|
后记
测试时候发现,/user下面的session会保存成功,但是到了/orderForm时,不会自动加上session,会在生成一个session,查看cookie就能发现有两个JSESSION,但是路径不一样。我的处理方式是在cookieUtil里面设置路径的path设置为”/“。
1 2 3 4 5 6 7 8 9 10 11
| public static HttpCookie generateSetCookie(HttpServletRequest request, String name, String value,Duration duration) { ResponseCookie cookie = ResponseCookie.from(name, value) .secure(true) .domain(domain) .path("/") .maxAge(duration) .sameSite("None") .build() ; return cookie; }
|