跨域问题
Ajax常用解决方法
-
使用
@CrossOrigin
注解- 最简单的,覆盖最广的方法
- 使用方法:在controller类上或controller类中方法上添加注解即可
- 参数:https://zhuanlan.zhihu.com/p/66789473
- 基本参数:
- origins : 允许可访问的域列表,匹配的域名是跨域预请求 Response 头中的 ‘Access-Control-Aloow_origin’ 字段值。不设置确切值时默认支持所有域名跨域访问。
- **maxAge ** : 准备响应前的缓存持续的最大时间(以秒为单位),对应的是是跨域请求 Response 头中的 ‘Access-Control-Max-Age’ 字段值,表示预检请求响应的缓存持续的最大时间,目的是减少浏览器预检请求/响应交互的数量。默认值1800s。设置了该值后,浏览器将在设置值的时间段内对该跨域请求不再发起预请求。
- 其他参数:
- allowedHeaders: 跨域请求中允许的请求头中的字段类型, 该值对应跨域预请求 Response 头中的 ‘Access-Control-Allow-Headers’ 字段值。 不设置确切值默认支持所有的header字段(Cache-Controller、Content-Language、Content-Type、Expires、Last-Modified、Pragma)跨域访问。
- exposedHeaders: 跨域请求请求头中允许携带的除Cache-Controller、Content-Language、Content-Type、Expires、Last-Modified、Pragma这六个基本字段之外的其他字段信息,对应的是跨域请求 Response 头中的 'Access-control-Expose-Headers’字段值。
- methods: 跨域HTTP请求中支持的HTTP请求类型(GET、POST…),不指定确切值时默认与 Controller 方法中的 methods 字段保持一致。
- allowCredentials: 该值对应的是是跨域请求 Response 头中的 ‘Access-Control-Allow-Credentials’ 字段值。浏览器是否将本域名下的 cookie 信息携带至跨域服务器中。默认携带至跨域服务器中,但要实现 cookie 共享还需要前端在 AJAX 请求中打开 withCredentials 属性。
- 基本参数:
- 要求
- springMVC的版本要在4.2或以上版本才支持
- JDK版本在
java 7 version (7u80)
以上才支持,否则会编译报错:
- 源码讲解:https://zhuanlan.zhihu.com/p/66789473
-
jsonp
-
使用较多,但缺陷明显的方法,不推荐
-
使用方法
-
最简单应用:前端:ajax请求中
dataType
属性改为jsonp
,type
属性改为get
-
后端:
-
接收参数中多一个
String
类型的callback
参数(SpringMVC直接在方法参数中添加该参数即可,servlet则 getParameter()方法获取即可) -
将返回数据进行jsonp处理(可选两种方式):
-
SpringMVC的@RequestMapping()注解指定
produces = {“application/javascript;charset=UTF-8”}
,再数据与上述callback
参数进行以下方式的拼接{result}=callback +"(" {result} ")";
(servlet直接进行拼接OutputStream流返回即可)
-
该方式只支持SpringMVC4.2版本以上:将数据进行以下处理即可
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result); mappingJacksonValue.setJsonpFunction(callback); return mappingJacksonValue;
-
-
-
-
其他参数:(ajax中可配置的参数)
jsonp
:(默认:“callback”): JSONP回调查询参数的名称- 若修改,后端中参数名称也要对应修改
jsonpCallback
(默认: “jsonp{N}”): 全局JSONP回调函数的 字符串(或返回的一个函数)名。设置该项能启用浏览器的缓存cache
(默认: true): 浏览器是否应该被允许缓存GET响应。从v1.1.4开始,当dataType选项为"script"
或jsonp
时,默认为false
。
-
缺陷
- 只能发送 GET 请求,无法发送其他类型的请求
- ajax中无法携带自定义请求头,否则会报400的状态码,而且该请求不会发送至目标服务器就直接返回400状态码
-
-
WebMvcConfigurerAdapter配置类
-
作用范围与
@CrossOrigin
注解相同,但配置方法相对更复杂一些 -
使用方法:在spring项目中新建一个配置类即可,如下
@Configuration @EnableWebMvc public class CorsConfig extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry corsRegistry){ /** * 所有请求都允许跨域,使用这种配置就不需要 * 在interceptor中配置header了 */ corsRegistry.addMapping("/**") .allowCredentials(true) .allowedOrigins("*") .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") .allowedHeaders("*") .maxAge(3600); } }
-
Spring Boot项目的话使用以下代码
@SpringBootConfiguration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry corsRegistry){ /** * 所有请求都允许跨域,使用这种配置就不需要 * 在interceptor中配置header了 */ corsRegistry.addMapping("/**") .allowCredentials(true) .allowedOrigins("*") .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") .allowedHeaders("*") .maxAge(3600); } }
-
-
-
JSONP与其他两种方式的比较
- CORS与JSONP的使用目的相同,但是比JSONP更强大。
- JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
其他跨域问题解决方法
-
基于filter的跨域实现
-
该方式也是ajax请求跨域的一种处理方法,但较为复杂
-
使用方法:(找到三种实现,具体用哪个没有验证)
-
SpringBoot
@Configuration public class MyConfiguration { @Bean public FilterRegistrationBean corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(0); return bean; } }
-
SpringMVC
@Configuration public class HttpFilterConfig { @Bean public FilterRegistrationBean<CorsFilter> corsFilter() { CorsConfiguration corsConfig = new CorsConfiguration(); corsConfig.setAllowCredentials(true); corsConfig.addAllowedOrigin(CorsConfiguration.ALL); corsConfig.addAllowedMethod(CorsConfiguration.ALL); corsConfig.addAllowedHeader(CorsConfiguration.ALL); //默认可不设置这个暴露的头。这个为了安全问题,不能使用*。设置成*,后面会报错:throw new IllegalArgumentException("'*' is not a valid exposed header value"); //corsConfig.addExposedHeader(""); corsConfig.setMaxAge(3600L); UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); configSource.registerCorsConfiguration("/**", corsConfig); FilterRegistrationBean<CorsFilter> corsBean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(configSource)); corsBean.setName("crossOriginFilter"); corsBean.setOrder(0);//这个顺序也有可能会有影响,尽量设置在拦截器前面 return corsBean; } }
-
未知
@Configuration public class CorsConfig{ private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址 corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头 corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法 return corsConfiguration; } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", buildConfig()); // 4 对接口配置跨域设置 return new CorsFilter(source); } }
-
-
-
XML命名空间
-
该方式也是ajax请求跨域的一种处理方法,但需要新建一个SpringMVC的xml文件,SpringBoot如何配置未知
-
使用方法
-
简单配置
<mvc:cors> <mvc:mapping path="/**" /> </mvc:cors>
-
复杂配置
<mvc:cors> <mvc:mapping path="/**" allowed-origins="*" allowed-methods="'POST', 'GET', 'PUT', 'OPTIONS', 'DELETE'" allowed-headers="*" exposed-headers="*" allow-credentials="false" max-age="3600" /> </mvc:cors>
-
-
iframe与主站资源跨域问题解决: