转载

spring-boot + jsonp 解决前端跨域问题

现在咱们一起来讨论浏览器跨域请求数据的相关问题。说这样可能不是很标准,因为拒绝跨域请求数据并不是浏览器所独有的,之所以会出现跨域请求不了数据,是因为浏览器基本都实现了一个叫"同源策略"的安全规范。该规范具体是什么呢?我们在MDN上找到了一份资料,地址如下:

浏览器同源策略讲解

总的来说,当A网址和B网址在 协议端口域名 方面存在不同时,浏览器就会启动同源策略,拒绝A、B服务器之间进行数据请求。

说了同源策略,纸上得来终觉浅,绝知此事要躬行,到底同源策略是怎么体现的呢?下面我将结合代码一步一步进行演示。

1、A服务器请求不了B服务器的情况

既然是跨域,我就假设我有两个域名,分别是 Alocalhost , A 表示小编在阿里云上主机域名, localhost 顾名思义就是小编的开发机器了。我们想象这样一个场景,在 localhost 上部署一个 index.html 文件,在 A 服务器上部署一个简单的 spring-boot 后台服务,并提供一个简单的接口暴露给 index.html 文件调用,最后浏览器请求 localhostindex.html 文件,看浏览器提示什么?

index.html

<!DOCTYPE html>
<html>
<head>
<title>测试跨域访问</title>
<meta charset="utf-8"/>
</head>
<body>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function() {
            $.ajax({
                type : "get",
                async : true,
                url : "http://A/hello/map/getUser.json",// 请求A服务器上的接口
                type : "json",
                success : function(data) {
                // 打印返回的数据
                console.log("success,and return data is " + data);
                }
            });
        });
    </script>
        <h2>hello world</h2>
</body>
</html>

浏览器上请求 index.html 文件,显示如下:

spring-boot + jsonp 解决前端跨域问题

可以发现,请求被浏览器给拒绝了,提示我们不允许跨域请求数据,很难受,怎么解决呢?

2、使用 jsonp 解决跨域请求

首先讲下原理,jsonp解决跨域问题主要利用了 <script> 标签的可跨域性,也就是 src 属性中的链接地址可以跨域访问的特性,因为我们经常将 src 属性值设置为cdn的地址,已加载相关的js库。

index.html

<!DOCTYPE html>
<html>
<head>
<title>测试跨域访问</title>
<meta charset="utf-8" />
</head>
<body>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript">
    	$(document).ready(function() {
        	$.ajax({
        		type : "get",
        		async : true,
        		jsonp : "callbackName",// 后端接口参数名
        		jsonpCallback : "callbackFunction", // 回调函数名
        		url : "http://A/hello/map/getUser.json",
        		dataType : "jsonp", // 数据格式为 jsonp
        		success : function(data) {
        			console.log("success");
        		}
        	});
    	});
    </script>
    <script type="text/javascript">
    	var callbackFunction = function(data) {
    		alert('接口返回的数据是:' + JSON.stringify(data));
    	};
    </script>
</body>
</html>

A 服务器上的接口代码为:

/**
 * 
 * The class JsonBackController.
 *
 * Description:该控制器返回一串简单的json数据,json数据由一个简单的User对象组成
 *
 * @author: huangjiawei
 * @since: 2018年6月12日
 * @version: $Revision$ $Date$ $LastChangedBy$
 *
 */
@RestController
@RequestMapping(value = "/map")
public class JsonBackController {
    private static final Logger logger = LoggerFactory.getLogger(JsonBackController.class);
    /**
     * 解决跨域请求数据
     * @param response
     * @param callbackName 前端回调函数名
     * @return
     */
    @RequestMapping(value = "getUser.json")
    public void getUser(HttpServletResponse response, @RequestParam String callbackName) {
        User user = new User("huangjiawei", 22);
        response.setContentType("text/javascript");
        Writer writer = null;
        try {
        	writer = response.getWriter();
        	writer.write(callbackName + "(");
        	writer.write(user.toString());
        	writer.write(");");
        } catch (IOException e) {
        	logger.error("jsonp响应写入失败! 数据:" + user.toString(), e);
        } finally {
        	if (writer != null) {
        		try {
        			writer.close();
        		} catch (IOException e) {
        			logger.error("输出流关闭异常!", e);
        		}
        		writer = null;
        	}
        }
    }
}

后端传入一个参数 callbackName 回调函数名,然后返回一段js代码给前端,js代码格式如下:

callbackName + ( data ) + ;

浏览器请求 localhost 服务器上的 index.html 文件,结果如下:

spring-boot + jsonp 解决前端跨域问题

上面这种方式是通过 jquery + jsonp 解决跨域问题的,刚刚不是说可以用 <script> 标签的 src 属性吗?四的。

localhost 服务器上的 index.html

<!DOCTYPE html>
<html>
<head>
<title>测试跨域访问</title>
<meta charset="utf-8" />
</head>
<body>
	<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
	<script type="text/javascript">
		var callbackFunction = function(data) {
			alert('接口返回的数据是:' + JSON.stringify(data));
		};
	</script>
	<script type="text/javascript" src="http://A/hello/map/getUser.json?callbackName=callbackFunction"></script>
</body>
</html>

浏览器显示效果和上面一致。但此处需要注意的是, src 表示引入一个js文件,由于是直接调用接口,而接口返回的数据又刚好是一段js代码,故能被执行。另外,第二个 <script> 标签顺序不能颠倒,不然会出现 callbackFunction 函数找不到的情况。

工程代码地址 : github.com/SmallerCode…

最后总结下,解决跨域的方案有很多种,jsonp只是其中一种,具体情况需要具体分析。希望此文对你有帮助,谢谢阅读,欢迎github给颗 start ,么么哒!

原文  https://juejin.im/post/5b1f8bc05188257d7541c2ce
正文到此结束
Loading...