ajax跨域携带cookie需要增加一个参数,xhrFields:{withCredentials:true},而且这个时候的cookie是种在服务端接口域里面的,而不是页面所在的域。
服务端解决跨域问题的时候,会设置允许哪些Origin,Method,如果是跨域携带cookie的异步请求,这个允许的域只能是唯一的,不能使用通配符*,也不能同时设置多个域。同时还需要保证参数Access-Control-Allow-Credentials为true。
下面通过示例演示:
前端页面通过node框架koa库启动一个server,访问地址:http://localhost:3000/,默认会加载静态页面index.html。
index.html
cookie
服务端使用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 test(@CookieValue(value = "name")String name){
Map 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。