前后端分离跨域问题的⼏种解决⽅案
前后端分离跨域问题的⼏种解决⽅案
⼀、为什么会出现跨域问题?
出于浏览器的同源策略限制。
同源策略(Sameoriginpolicy)是⼀种约定,它是浏览器最核⼼也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的⼀种实现。同源策略会阻⽌⼀个域的javascript脚本和另外⼀个域的内容进⾏交互。所谓同源(即指在同⼀个域)就是两个页⾯具有相同的协议(protocol),主机(host)和端⼝号(port)。
⼆、什么是跨域?
ajax实例 文件浏览当⼀个请求url的协议、域名、端⼝三者之间任意⼀个与当前页⾯url不同即为跨域。
当前页⾯url被请求页⾯url是否跨域原因
否同源(协议、域名、端⼝号相同)
跨域协议不同(http/https)
跨域主域名不同(test/baidu)
跨域⼦域名不同(www/blog)
跨域端⼝号不同(8080/7001)
两个相同的源之间浏览器默认其是可以相互访问资源和操作DOM的。
两个不同的源之间若想要相互访问资源或者操作DOM,那么会有⼀套基础的安全策略的制约。
具体有如下两⽅⾯的限制:
1.安全性:浏览器要防⽌当前站点的私密数据不会向其他站点发送如当前站点的Cookie,LocalStorage,IndexDb不会被发送到其他站点
或被其他站点脚本读取到⽆法跨域获取Dom,⽆法发送Ajax请求。
2.可⽤性:⼤型站点的图⽚,⾳视频等资源,希望部署在独⽴服务器上,为缓解当前服务的压⼒,开放某些特定的⽅式,访问⾮同源
站点如:<script><img><iframe><link><vedio>等,可以同src属性跨域访问允许跨域提交表单/或重定向请求。
三、解决⽅案
1.后台服务端解决⽅案
⽅法⼀:@CrossOrigin
/**
注意:
1、springMVC的版本要在4.2或以上版本才⽀持@CrossOrigin
2、⾮@CrossOrigin没有解决跨域请求问题,⽽是不正确的请求导致⽆法得到预期的响应,导致浏览器端提⽰跨域问题。
3、在Controller注解上⽅添加@CrossOrigin注解后,仍然出现跨域问题,
解决⽅案之⼀就是:在@RequestMapping注解中没有指定Get、Post⽅式,具体指定后,问题解决。
其中@CrossOrigin中的2个参数:
origins  :允许可访问的域列表
maxAge:准备响应前的缓存持续的最⼤时间(以秒为单位)。
可以配置在Controller上也可以配置在⽅法上
*/
@CrossOrigin
@RestController
public class person{
@RequestMapping(method = RequestMethod.GET)
public String add() {
// 若⼲代码
}
}
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
}
⽅法⼆:
package cn.pconline.fig;
import t.annotation.Bean;
import t.annotation.Configuration;
import org.s.CorsConfiguration;
import org.s.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1允许任何域名使⽤
corsConfiguration.addAllowedHeader("*"); // 2允许任何头
corsConfiguration.addAllowedMethod("*"); // 3允许任何⽅法(post、get等)
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
return new CorsFilter(source);
}
}
2.Nginx代理服务器,反向代理接⼝请求
location /api{
rewrite ^/api/(.*)$ /$1 break;
proxy_pass localhost:8081/;
}
3.jsonp⽅式
我这⾥简单的描述⼀下,不懂的可以参考
JSONP是怎么产⽣的:
1、浏览器的同源策略限制,Ajax直接请求普通⽂件存在跨域⽆权限访问的问题,甭管你是静态页⾯、动态⽹页、web服务、WCF,只要是跨域请求,⼀律不准;
2、不过Web页⾯上调⽤js⽂件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能⼒,⽐
如<script>、<img>、<iframe>);
3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等⽅式不算)跨域访问数据就只有⼀种可能,那就是在远程服务器上设法把数据装进js格式的⽂件⾥,供客户端调⽤和进⼀步处理;
4、恰巧我们已经知道有⼀种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原⽣⽀持,所以在客户端⼏乎可以随⼼所欲的处理这种格式的数据;
5、这样⼦解决⽅案就呼之欲出了,web客户端通过与调⽤脚本⼀模⼀样的⽅式,来调⽤跨域服务器上动态⽣成的js格式⽂件(⼀般以JSON 为后缀),显⽽易见,服务器之所以要动态⽣成JSON⽂件,⽬的就在于把客户端需要的数据装⼊进去。
6、客户端在对JSON⽂件调⽤成功之后,也就获得了⾃⼰所需的数据,剩下的就是按照⾃⼰需求进⾏处理和展现了,这种获取远程数据的⽅式看起来⾮常像AJAX,但其实并不⼀样。
7、为了便于客户端使⽤数据,逐渐形成了⼀种⾮正式传输协议,⼈们把它称作JSONP,该协议的⼀个
要点就是允许⽤户传递⼀个callback 参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制⾃⼰的函数来⾃动处理返回数据了。
具体原理:
服务端提供的js脚本是动态⽣成的,这样调⽤者可以传⼀个参数过去告诉服务端“我想要⼀段调⽤XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来⽣成js脚本并响应了。
JS调⽤实例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
/
/ 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终⽣成的返回值都是⼀段javascript代码)
var url = "flightQuery/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = ateElement('script');
script.setAttribute('src', url);
// 把script标签加⼊head,此时调⽤开始
</script>
</head>
<body>
</body>
</html>
我们看到调⽤的url中传递了⼀个code参数,告诉服务器我要查的是CA1998次航班的信息,⽽callback参数则告诉服务器,我的本地回调函数叫做flightHandler,所以请把查询结果传⼊这个函数中进⾏调⽤。
OK,服务器很聪明,这个叫做flightResult.aspx的页⾯⽣成了⼀段这样的代码提供给jsonp.html(服务端的实现这⾥就不演⽰了,与你选⽤的语⾔⽆关,说到底就是拼接字符串):
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
我们看到,传递给flightHandler函数的是⼀个json,它描述了航班的基本信息。运⾏⼀下页⾯,成功弹出提⽰窗⼝,jsonp的执⾏全过程顺利完成!
JQuery调⽤实例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="/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: "flightQuery/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>
是不是有点奇怪?为什么我这次没有写flightHandler这个函数呢?⽽且竟然也运⾏成功了!哈哈,这就是jQuery的功劳了,jquery在处理jsonp类型的ajax时(还是忍不住吐槽,虽然jquery也把jsonp归⼊了ajax,但其实它们真的不是⼀回事⼉),⾃动帮你⽣成回调函数并把数据取出来供success属性⽅法来调⽤,是不是很爽呀?

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。