一般解决跨域问题可以通过 CORS、JSONP 和反向代理。下面分别介绍这三种方式。

1、CORS

如果接口需要携带 Cookie、Authorization 等凭证,后端不能把 Access-Control-Allow-Origin 直接设置为 *,必须返回具体允许的 Origin,并同时设置 Access-Control-Allow-Credentials: true。如果不需要凭证,才适合使用 * 简化配置。

以 Netty 为例,支持跨域请求需要配置返回头信息。

1
2
3
4
5
6
7
8
9
10
11
FullHttpResponse response = null;
String responseStr = result.toString() + "your-secret-salt";
response.headers().set("response", MD5Util.getMD5Code(responseStr, true));
response.headers().set(HttpHeaderNames.ACCESS_CONTROL_EXPOSE_HEADERS, "response"); // 暴露给前端读取的自定义响应头
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); // 不携带凭证时可以使用 *
response.headers().set(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS, "*");
response.headers().set("Access-Control-Allow-Headers", "PLATFORM,H5TOKEN,sign,UUID,RESOURCEPLATFORM,response"); // 根据实际情况配置
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
ctx.writeAndFlush(response);

Spring 全局配置:

1
2
3
4
5
6
7
8
9
10
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://192.168.89.89") // 根据实际情况配置;allowCredentials(true) 时不能写 *
.allowedMethods("GET", "POST","DELETE")
.allowCredentials(false).maxAge(3600);
}
}

Spring 单接口配置:

1
2
3
4
5
6
@CrossOrigin(origins = "*", maxAge = 3600) // 不携带凭证时可以使用 *;携带凭证时应改成具体域名
@PostMapping("save")
public ResponseEntity<Result> addNote(@RequestParam String noteName) {
//
}

2、JSONP

AJAX 与 JSONP 的异同:
1、AJAX 和 JSONP 这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个 URL,然后处理服务器返回的数据。因此 jQuery 和 Ext 等框架都把 JSONP 作为 AJAX 的一种形式进行了封装。
2、但 AJAX 和 JSONP 本质上是不同的东西。AJAX 的核心是通过 XMLHttpRequest 获取非本页内容,而 JSONP 的核心是动态添加 script 标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Untitled Page</title>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
$.ajax({
type: "get",
async: false,
url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(json){
alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
},
error: function(){
alert('fail');
}
});
});
</script>
</head>
<body>
</body>
</html>

3、反向代理

配置 Nginx 就可以实现跨域,一般在生产环境采用这种方式。具体配置如下:

1
2
3
4
5
6
7
location /ticketManagement/ {
proxy_pass http://127.0.0.1:9001/;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
}