mirror of
https://gitee.com/wangkang/udf.git
synced 2026-10-23 01:43:40 +00:00
252 lines
7.3 KiB
Markdown
252 lines
7.3 KiB
Markdown
# spring boot / cloud (六) 开启CORS跨域访问
|
|
|
|
##前言
|
|
|
|
|
|
###什么是CORS?
|
|
|
|
|
|
>Cross-origin resource sharing(跨域资源共享),是一个W3C标准,它允许你向一个不同源的服务器发出XMLHttpRequest请求,从而克服了ajax只能请求同源服务的限制.并且也可以通过灵活的设置,来指定什么样的请求是可以被授权的.
|
|
|
|
|
|
###什么是跨域?
|
|
|
|
|
|
假设你在http://xxx.com/test/下有一个js文件,从这个js里发出一个ajax请求请求后端服务,按照如下情况判定:
|
|
|
|
|
|
| 请求地址 | 原因 | 结果 |
|
|
| ------------- |:-------------:| -----:|
|
|
| http://xxx.com/xxxx/action | 同一域名,不同文件夹 | 非跨域 |
|
|
| http://xxx.com/test/action | 同一域名,同一文件夹 | 非跨域 |
|
|
| http://a.xxx.com/test/action | 不同域名,文件路径相同 | 跨域 |
|
|
| http://xxx.com:8080/test/action | 同一域名,不同端口 | 跨域 |
|
|
| https://xxx.com/test/action | 同一域名,不同协议 | 跨域 |
|
|
|
|
|
|
###还有那些其他的跨域解决方案?
|
|
|
|
|
|
- **JSONP** : 动态添加一个`<script>`标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了,而缺点也很明显,它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题
|
|
|
|
|
|
- **NGINX代理** : 通过一个代理服务器,将跨域的请求转发,如:前端JS在http://www.demo.com/a.js,后端是http://www.abc.com/app/action,通过代理可将后端的地址转换成http://www.demo/app/action,这样,从前端发起的请求,就不存在跨域的情况了
|
|
|
|
|
|
**然后CORS是支持所有类型的HTTP请求,并且也只是服务端进行设置即可,但是缺点就是老的浏览器不支持CORS(如:IE7,7,8,等)**
|
|
|
|
|
|
##思路
|
|
|
|
|
|
###CORS的响应头
|
|
|
|
|
|
- **Access-Control-Allow-Origin** : 必须的,允许的域名,如果设置*,则表示接受任何域名
|
|
|
|
|
|
- **Access-Control-Allow-Credentials** : 非必须的,表示是否允许发送Cookie,注意,当设置为true的时候,客户端的ajax请求,也需要将withCredentials属性设置为true
|
|
|
|
|
|
- **Access-Control-Expose-Headers** : 非必须的,表示客户端能拿到的header,默认情况下`XMLHttpRequest`的`getResponseHeader`方法只能拿到几个基本的header,如果有自定义的header要获取的话,则需要设置此值
|
|
|
|
|
|
- **Access-Control-Request-Method** : 必须的,表示CORS上会使用到那些HTTP方法
|
|
|
|
|
|
- **Access-Control-Request-Headers** : 必须的,表示CORS上会有那些额外的的有信息
|
|
|
|
|
|
###CORS将请求分为两种类型
|
|
|
|
|
|
####两种类型分别为`简单请求`和`非简单请求`,同时满足以下两大条件的请求被定义为是`简单请求`:
|
|
|
|
|
|
- 请求方法是以下三种之一:
|
|
|
|
|
|
- HEAD
|
|
|
|
|
|
- GET
|
|
|
|
|
|
- POST
|
|
|
|
|
|
- HTTP头信息不超出以下几种字段:
|
|
|
|
|
|
- Accept
|
|
|
|
|
|
- Accept-Language
|
|
|
|
|
|
- Content-Language
|
|
|
|
|
|
- Last-Event-ID
|
|
|
|
|
|
- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
|
|
|
|
|
|
###对于`非简单请求`,浏览器会自动发一个`预检请求`,这个请求是`OPTIONS`方法的,主要是询问服务器当前请求是否在允许范围内
|
|
|
|
|
|
##实现
|
|
|
|
|
|
###1.方式A:使用@CrossOrigin来标记指定的方法(小范围跨域)
|
|
|
|
|
|
``` java
|
|
@RequestMapping(value = "add", method = RequestMethod.GET)
|
|
@CrossOrigin(methods = { RequestMethod.GET, RequestMethod.POST }, origins = "*")
|
|
public RestResponse<Integer> add(Integer a, Integer b) {
|
|
return new RestResponse<>(demoService.add(a, b));
|
|
}
|
|
```
|
|
|
|
###2.方式B:使用spring boot的默认配置来设定全局跨域
|
|
|
|
|
|
``` java
|
|
endpoints.cors.allow-credentials=
|
|
endpoints.cors.allowed-headers=
|
|
endpoints.cors.allowed-methods=GET
|
|
endpoints.cors.allowed-origins=
|
|
endpoints.cors.exposed-headers=
|
|
endpoints.cors.max-age=1800
|
|
```
|
|
|
|
###3.方式C:使用WebMvcConfigurer自定义配置跨域
|
|
|
|
|
|
####定义CorsRegistrationConfig类
|
|
|
|
``` java
|
|
public static class CorsRegistrationConfig {
|
|
//描述 : 扫描地址
|
|
private String mapping = "/**";
|
|
//描述 : 允许证书
|
|
private Boolean allowCredentials = null;
|
|
//描述 : 允许的域
|
|
private String allowedOrigins = "*";
|
|
//描述 : 允许的方法
|
|
private String allowedMethods = "POST,GET,DELETE,PUT";
|
|
//描述 : 允许的头信息
|
|
private String allowedHeaders = "*";
|
|
|
|
.........省略
|
|
}
|
|
```
|
|
|
|
|
|
####定义CorsConfig类
|
|
|
|
``` java
|
|
@Configuration
|
|
@ConfigurationProperties(prefix = "org.itkk.cors")
|
|
@Validated
|
|
public class CorsConfig {
|
|
|
|
//描述 : 跨域信息
|
|
@NotNull
|
|
private Map<String, CorsRegistrationConfig> config;
|
|
|
|
.....省略
|
|
|
|
}
|
|
```
|
|
|
|
|
|
####定义重写addCorsMappings方法
|
|
|
|
``` java
|
|
@Bean
|
|
public WebMvcConfigurer corsConfigurer() {
|
|
return new WebMvcConfigurerAdapter() {
|
|
@Override
|
|
public void addCorsMappings(CorsRegistry registry) {
|
|
//扫描地址
|
|
if (!CollectionUtils.isEmpty(config)) {
|
|
Iterator<String> keys = config.keySet().iterator();
|
|
while (keys.hasNext()) {
|
|
String key = keys.next();
|
|
CorsRegistrationConfig item = config.get(key);
|
|
CorsRegistration cr = registry.addMapping(item.getMapping());
|
|
if (item.getAllowCredentials() != null) {
|
|
cr.allowCredentials(item.getAllowCredentials());
|
|
}
|
|
if (StringUtils.isNotBlank(item.getAllowedOrigins())) {
|
|
String[] allowedOriginArray = item.getAllowedOrigins().split(",");
|
|
cr.allowedOrigins(allowedOriginArray);
|
|
}
|
|
if (StringUtils.isNotBlank(item.getAllowedMethods())) {
|
|
String[] allowedMethodArray = item.getAllowedMethods().split(",");
|
|
cr.allowedMethods(allowedMethodArray);
|
|
}
|
|
if (StringUtils.isNotBlank(item.getAllowedHeaders())) {
|
|
String[] allowedHeaderArray = item.getAllowedHeaders().split(",");
|
|
cr.allowedHeaders(allowedHeaderArray);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
|
|
####配置文件,可根据不同的mapping设置不同的cors规则
|
|
|
|
``` java
|
|
org.itkk.cors.config.demo.mapping=/**
|
|
org.itkk.cors.config.demo.allowCredentials=
|
|
org.itkk.cors.config.demo.allowedOrigins=
|
|
org.itkk.cors.config.demo.allowedMethods=
|
|
org.itkk.cors.config.demo.allowedHeaders=
|
|
```
|
|
|
|
|
|
####使用jquery,在跨域场景下进行测试
|
|
|
|
``` javascript
|
|
$(function(){
|
|
$.ajax({
|
|
url:'http://127.0.0.1:8080/demo/c',
|
|
headers:{
|
|
'aheader':'111'
|
|
},
|
|
type:'GET',
|
|
dataType:'json',
|
|
success:function(data){
|
|
console.log(1);
|
|
console.log(data);
|
|
console.log(2);
|
|
|
|
}
|
|
});
|
|
});
|
|
```
|
|
|
|
## **代码仓库** (博客配套代码)
|
|
|
|
- [udf-starter : 基础项目,脚手架,框架](https://gitee.com/wangkang/udf)
|
|
|
|
- [udf-sample : 集成样例](https://gitee.com/wangkang/udf-sample)
|
|
|
|
##结束
|
|
|
|
演示了单spring boot的应用的,在后续的章节中,会找机会写一下在微服务场景下(spring cloud)的跨域设置
|
|
|
|
---------
|
|
|
|
想获得最快更新,请关注公众号
|
|
|
|

|
|
|