1. 什么是 跨域请求
跨域请求是指浏览器向不同域名的服务器发送请求,例如从http://www.a.com
向http://www.b.com
发送请求。由于浏览器的同源策略,跨域请求会受到限制,需要服务器端或客户端进行处理。同源策略是为了保证用户信息的安全,防止恶意的网站窃取数据。
举例说明:
假设运行在http://www.a.com
的网页应用想要访问http://www.b.com/data.json
的资源。网页中可能包含类似于下面的 JavaScript 代码:
const xhr = new XMLHttpRequest();
const url = 'http://www.b.com/data.json';
xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();
这段代码会发起一个跨域请求,因为请求的 URL 的协议、域名和端口与当前页面的 URL 不同。如果服务器端没有设置允许跨域访问的响应头,浏览器就会拒绝接收响应,并在控制台报错。
浏览器安全的基石是「同源策略」(same-origin policy)。同源即:
- 协议相同
- 域名(主机名)相同
- 端口相同
同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。一个页面:
- 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
- 无法接触非同源网页的 DOM
- 无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)
一个源访问另一个源的资源时即为「跨源」,最常见的跨源场景是域名不同,即常说的“跨域”。有时候我们不得不进行跨域请求,那么应该如何解决呢?目前主要有以下方案:
- JSONP(JSON with Padding)
- CORS(Cross-Origin Resource Sharing)
- Websocket
- 在 nginx 等反向代理服务器中设置为同一域名
本文介绍了几种在JAVA后端实现跨域请求的方法。
2 . JAVA后端实现跨域请求
2.1 方法一:CORS
CORS(Cross-Origin Resource Sharing)是一种标准的跨域解决方案,它允许服务器在响应头中添加一些特定的字段,来告诉浏览器可以接受哪些域名的请求,以及可以使用哪些方法和头部信息。浏览器在收到响应后,会根据这些字段判断是否允许跨域请求。
要使用CORS,我们需要在JAVA后端设置响应头,例如:
// 设置允许跨域的域名,*表示所有域名
response.setHeader("Access-Control-Allow-Origin", "*");
// 设置允许跨域的方法,如GET, POST, PUT, DELETE等
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
// 设置允许跨域的请求头,如Content-Type, Authorization等
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
这样,浏览器就可以正常发送跨域请求了。
2.2 方法二:JSONP
JSONP(JSON with Padding)是一种利用<script>标签的特性来实现跨域请求的方法。它的原理是,浏览器可以通过<script>标签加载任何域名的脚本文件,而脚本文件中可以包含JSON格式的数据,并通过一个回调函数来处理。服务器端需要根据请求参数中指定的回调函数名来返回数据。
要使用JSONP,我们需要在前端发送一个带有回调函数名的参数,例如:
// 前端发送一个带有callback参数的请求
<script src="http://www.b.com/data?callback=handleData"></script>
然后,在后端返回一个包含回调函数调用的脚本,例如:
// 后端返回一个包含回调函数调用的脚本
handleData({"name":"Alice","age":18});
这样,浏览器就会执行handleData函数,并传入JSON数据作为参数。
2.3 方法三:代理
代理是一种通过中间服务器来转发跨域请求的方法。它的原理是,浏览器向同源的代理服务器发送请求,代理服务器再向目标服务器发送请求,并将响应返回给浏览器。这样,浏览器就不会直接与目标服务器进行通信,而是通过代理服务器来绕过同源策略。
要使用代理,我们需要在JAVA后端搭建一个代理服务器,并将前端的请求转发给目标服务器,例如:
// 创建一个URL对象,表示目标服务器的地址
URL url = new URL("http://www.b.com/data");
// 打开一个连接对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置连接属性
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setDoOutput(true);
// 获取输入流和输出流
InputStream in = conn.getInputStream();
OutputStream out = response.getOutputStream();
// 将输入流中的数据复制到输出流中
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
// 关闭流和连接
in.close();
out.close();
conn.disconnect();
这样,前端就可以通过代理服务器来获取目标服务器的数据了。
3. 三种方案 对比
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
JSONP | 兼容性好,支持低版本浏览器 | 只支持GET请求,需要服务器端配合,不能自定义请求头和响应头,安全性较低 | 只需要读取数据,不需要修改数据,且对安全性要求不高的情况 |
CORS | 支持各种类型的HTTP请求,可以自定义请求头和响应头,安全性较高 | 需要服务器端开启CORS支持,且不支持低版本浏览器 | 需要读写数据,且对安全性要求较高的情况 |
代理 | 可以绕过浏览器的同源策略,不需要修改服务器端的配置,可以支持任何类型的HTTP请求 | 需要额外搭建一个代理服务器,增加了网络开销和维护成本 | 无法修改服务器端配置,或者需要访问第三方服务器的数据的情况 |
4. 总结
本文介绍了三种在JAVA后端实现跨域请求的方法,分别是CORS,JSONP和代理。每种方法都有其优缺点,具体应用时需要根据实际情况选择合适的方法。希望本文对你有所帮助
5. 参考资料:
1: So, JSONP or CORS? - Stack Overflow
3: 三种方法解决跨域问题JSONP、CORS、代理转发 - CSDN博客
4: Cors跨域(四):解决方案对决JSONP vs CORS(下) - 阿里 …