带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跨域请求问题的主要内容,如果未能解决你的问题,请参考以下文章

jQuery+ASP.NET MVC基于CORS实现带cookie的跨域ajax请求

前端Jquery-Ajax跨域请求,并携带cookie

Ajax跨域请求携带cookie问题

ajax跨域请求无法携带cookie的问题

关于ajax异步请求不到数据的问题 302跨域请求

ajax、fetch 跨域携带cookie