1、跨域:浏览器同源策略

1995年,同源策略由Netscape公司引入浏览器。目前,所有浏览器都实行这个策略

最初,它的含义是指,A网页设置的Cookie,B网页不能打开,除非这两个网页同源

所谓同源是指三个相同,域名相同、协议相同、端口相同

也就是说,浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域

浏览器控制台跨域提示:

No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘null’ is therefore not allowed access.

2、解决方法

1)、JSONP

JSONP可以参考:

2)、Http响应头配置允许跨域

1)Nginx层配置:

nginx.conf配置参考:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    #gzip
    gzip on;
    gzip_min_length 1024;
    gzip_buffers 4 16k;
    gzip_comp_level 2;
    gzip_types *;
    gzip_vary on; 

    server {
        listen       8080;
        server_name  www.shop1.com;
        location / {
            root   /shop/products/;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    } 

    upstream shop{
	    server 192.168.126.144:9000;
	    server 192.168.126.144:9002;
    }
	
    server{
        listen       80;
        server_name  www.shop2.com;
        location / {
        	if ($request_method = OPTIONS ) {
            	add_header 'Access-Control-Allow-Origin' '*';
            	add_header 'Access-Control-Allow-Credentials' 'true';
            	add_header 'Access-Control-Allow-Methods' 'POST,GET,DELETE,OPTIONS';
            	add_header 'Access-Control-Allow-Headers' 'x-method-override,content-type,accept';
            	proxy_pass  http://shop; 
            	return 200;
         	}
         	if ($request_method != OPTIONS ){
             	add_header 'Access-Control-Allow-Origin' '*';
             	add_header 'Access-Control-Allow-Credentials' 'true';
             	add_header 'Access-Control-Allow-Methods' 'POST,GET,DELETE,OPTIONS';
             	add_header 'Access-Control-Allow-Headers' 'x-method-override,content-type,accept';
             	proxy_pass  http://shop;
         	}
		}
	}
}

可以参考:

2)程序代码中处理

A.使用Cookie跨域工具

B.@CrossOrigin注解

向@RequestMapping注解处理程序方法一样使用@CrossOrigin注解(默认情况下,@CrossOrigin允许在@RequestMapping注解中指定的所有源和HTTP方法)

@CrossOrigin的2个参数:

  • origins:允许可访问的域列表
  • maxAge:准备响应前的缓存持续的最大时间(以秒为单位)

C.使用全局配置

@Configuration
public class Cors extends WebMvcConfigurerAdapter {
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		// 允许跨域的路径
		registry.addMapping("/**")
				// 允许的源(某一个域名)
				.allowedOrigins("*")
				// 哪些方法进行跨域
				.allowedMethods("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH")
				// 允许资格健全
				.allowCredentials(true)
				// 默认设置为1800秒
				.maxAge(3600);
	}
}

但是这样配置可能造成SpringMVC中的Interceptor和Cors冲突:详情参考:

通过配置Filter解决

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
	@Bean
	public CorsFilter corsFilter() {
		CorsConfiguration config = new CorsConfiguration();
		config.addAllowedOrigin("*");
		config.setAllowCredentials(true);
		config.addAllowedMethod("*");
		config.addAllowedHeader("*");
		UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
		configSource.registerCorsConfiguration("/**", config);
		return new CorsFilter(configSource);
	}
}

注意:假如接口报错,则跨域配置不生效


Http响应头配置允许跨域的配置方法均可以配合此Cookie工具

public final class CookieUtils {

	/**
	 * 得到Cookie的值, 不编码
	 *
	 * @param request
	 * @param cookieName
	 * @return
	 */
	public static String getCookieValue(HttpServletRequest request, String cookieName) {
		return getCookieValue(request, cookieName, false);
	}

	/**
	 * 得到Cookie的值
	 *
	 * @param request
	 * @param cookieName
	 * @return
	 */
	public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
		Cookie[] cookieList = request.getCookies();
		if (cookieList == null || cookieName == null) {
			return null;
		}
		String retValue = null;
		try {
			for (int i = 0; i < cookieList.length; i++) {
				if (cookieList[i].getName().equals(cookieName)) {
					if (isDecoder) {
						retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
					} else {
						retValue = cookieList[i].getValue();
					}
					break;
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return retValue;
	}

	/**
	 * 得到Cookie的值
	 *
	 * @param request
	 * @param cookieName
	 * @return
	 */
	public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
		Cookie[] cookieList = request.getCookies();
		if (cookieList == null || cookieName == null) {
			return null;
		}
		String retValue = null;
		try {
			for (int i = 0; i < cookieList.length; i++) {
				if (cookieList[i].getName().equals(cookieName)) {
					retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
					break;
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return retValue;
	}

	/**
	 * 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue) {
		setCookie(request, response, cookieName, cookieValue, -1);
	}

	/**
	 * 设置Cookie的值 在指定时间内生效,但不编码
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage) {
		setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
	}

	/**
	 * 设置Cookie的值 不设置生效时间,但编码
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, boolean isEncode) {
		setCookie(request, response, cookieName, cookieValue, -1, isEncode);
	}

	/**
	 * 设置Cookie的值 在指定时间内生效, 编码参数
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage, boolean isEncode) {
		doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
	}

	/**
	 * 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
	 */
	public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage, String encodeString) {
		doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
	}

	/**
	 * 删除Cookie带cookie域名
	 */
	public static void deleteCookie(HttpServletRequest request, HttpServletResponse response, String cookieName) {
		doSetCookie(request, response, cookieName, "", -1, false);
	}

	/**
	 * 设置Cookie的值,并使其在指定时间内生效
	 *
	 * @param cookieMaxage
	 *            cookie生效的最大秒数
	 */
	private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage, boolean isEncode) {
		try {
			if (cookieValue == null) {
				cookieValue = "";
			} else if (isEncode) {
				cookieValue = URLEncoder.encode(cookieValue, "utf-8");
			}
			Cookie cookie = new Cookie(cookieName, cookieValue);
			if (cookieMaxage > 0)
				cookie.setMaxAge(cookieMaxage);
			cookie.setPath("/");
			response.addCookie(cookie);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 设置Cookie的值,并使其在指定时间内生效
	 *
	 * @param cookieMaxage
	 *            cookie生效的最大秒数
	 */
	private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
			String cookieValue, int cookieMaxage, String encodeString) {
		try {
			if (cookieValue == null) {
				cookieValue = "";
			} else {
				cookieValue = URLEncoder.encode(cookieValue, encodeString);
			}
			Cookie cookie = new Cookie(cookieName, cookieValue);
			if (cookieMaxage > 0)
				cookie.setMaxAge(cookieMaxage);
			cookie.setPath("/");
			response.addCookie(cookie);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}