带cookie的异步ajax跨域请求问题
Posted luffy5459
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带cookie的异步ajax跨域请求问题相关的知识,希望对你有一定的参考价值。
ajax跨域携带cookie需要增加一个参数,xhrFields:{withCredentials:true},而且这个时候的cookie是种在服务端接口域里面的,而不是页面所在的域。
服务端解决跨域问题的时候,会设置允许哪些Origin,Method,如果是跨域携带cookie的异步请求,这个允许的域只能是唯一的,不能使用通配符*,也不能同时设置多个域。同时还需要保证参数Access-Control-Allow-Credentials为true。
下面通过示例演示:
前端页面通过node框架koa库启动一个server,访问地址:http://localhost:3000/,默认会加载静态页面index.html。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cookie</title>
<style>
#root input{padding:10px;border:1px solid #ddd;color:#fff;border-radius: 3px;background: lightgreen;font-size: 16px;}
#root .box{padding:5px;}
#root textarea{width:790px;height:100px;resize: none;}
</style>
</head>
<body>
<div id="root">
<div class="box">
<input type="button" value="cookie" onclick="handleclick()"/>
</div>
<div class="box">
<textarea id="output"></textarea>
</div>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.js" ></script>
<script type="text/javascript">
var base_url = "http://localhost:8080"
function handleclick(){
$.ajax({
url:base_url+"/cookie/test",
type:"post",
xhrFields:{
withCredentials:true
},
success:function(res){
$("#output").val(JSON.stringify(res))
},
error:function(xhr,textStatus,errorThrown){
console.log(xhr)
}
})
}
</script>
</body>
</html>
服务端使用springboot,解决跨域通过配置Filter:
CookieController.java
package com.xxx.springboot.web;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/cookie")
public class CookieController {
@PostMapping("/test")
public Map<String, Object> test(@CookieValue(value = "name")String name){
Map<String, Object> map = new HashMap<>();
System.out.println("getCookie "+name);
map.put("code", 200);
map.put("msg", "success");
return map;
}
}
App.java
package com.xxx.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import com.xxx.springboot.config.MyCorsFilter;
@SpringBootApplication
public class App {
public static void main( String[] args ){
SpringApplication.run(App.class, args);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public FilterRegistrationBean registerFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.addUrlPatterns("/*");
bean.setFilter(new MyCorsFilter());
return bean;
}
}
MyCorsFilter.java
package com.xxx.springboot.config;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest)request;
String origin = req.getHeader("Origin");
System.out.println(origin);
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
}
1、 准备cookie,这个动作需要在http://localhost:8080域上完成:
虽然访问地址会有问题,因为没有静态页面可以加载,但是种个cookie还是可以的。
2、访问前端页面,发起ajax跨域请求:
点击页面按钮,报错。
报错详细信息:
Access to XMLHttpRequest at 'http://localhost:8080/cookie/test' from origin
'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-
Allow-Origin' header in the response must not be the wildcard '*' when the request's
credentials mode is 'include'. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
3、我们修改Filter的内容,让允许的域是http://localhost:3000,而不是所有域*。
访问正常,控制台也不报错。
在Filter中设置允许的Origin时,可以不用写死请求域,可以通过request获取请求域,然后设置响应头的Origin。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest)request;
String origin = req.getHeader("Origin");
//res.addHeader("Access-Control-Allow-Origin", "http://localhost:3000");
res.addHeader("Access-Control-Allow-Origin", origin);
res.addHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
携带cookie的异步跨域请求,最容易出错的地方在于服务端设置的允许Origin是所有或者多个Origin。它只能允许唯一的Origin。
以上是关于带cookie的异步ajax跨域请求问题的主要内容,如果未能解决你的问题,请参考以下文章