1.关于浏览器同源策略的说明
1.1 跨域
说明: 浏览器规定 当浏览器解析页面时,当遇到ajax请求时 如果请求与当前页面的 协议://域名:端口号都相同时,则满足同源策略 称之为同域请求.浏览器可以正确解析返回值 请求正常.
如果三者中有一项不同,则把请求称之为叫做跨域请求. 浏览器出于安全性的考虑 则不予解析返回值.
跨域:浏览器解析ajax时,违反了同源策略,就会发起跨域请求
远程请求的流程:
1.2 为什么会存在浏览器跨域限制?
既然目前各主流浏览器都存在跨域限制,那么为什么一定要存在这个限制呢?如果没有跨域限制会出现什么问题?
浏览器同源策略的提出本来就是为了避免数据安全的问题,即:限制来自不同源的“document”或脚本,对当前“document”读取或设置某些属性。
如果没有这个限制,将会出现什么问题?不妨看一下几个情形:
可能a.com的一段JavaScript脚本,在b.com未曾加载此脚本时,也可以随意涂改b.com的页面。
在浏览器中同时打开某电商网站(域名为b.com),同时在打开另一个网站(a.com),那么在a.com域名下的脚本可以读取b.com下的Cookie,如果Cookie中包含隐私数据,后果不堪设想。
因为可以随意读取任意域名下的Cookie数据,很容易发起CSRF攻击。
所以,同源策略是浏览器安全的基础,同源策略一旦出现漏洞被绕过,也将带来非常严重的后果,很多基于同源策略制定的安全方案都将失去效果。
1.3 对于浏览器来说,哪些资源(操作)会受到同源策略的限制?
对于浏览器来说,除了DOM,Cookie,XMLHttpRequest会受到同源策略的限制外,浏览器加载的一些第三方插件也有各自的同源策略。
最常见的一些插件如Flash,Java Applet,Silverlight,Google Gears等都有自己的控制策略。
另外,存储在浏览器中的数据,如LocalStorage和IndexedDB,以源进行分割。每个源都拥有自己单独的存储空间,一个源中的Javascript脚本不能对属于其它源的数据进行读写操作。
1.4 浏览器跨域限制会带来什么问题?
随着互联网的发展,对用户体验的要求越来越高,AJAX应用也就越发频繁,AJAX的本质就是XMLHttpRequest。
但XMLHttpRequest受到同源策略的约束,所以不能跨域访问资源,这与我们的期望是相违背的。
2解决跨域的方式
2.1.JSONP
2.1.1关于JSONP介绍
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的
2.1.2JSONP原理说明
1). 利用javaScript标签 动态获取远程数据
<script type="text/javascript" src="http://manage.jt.com/test.json"></script>
2).自定义回调函数
<script type="text/javascript">
/*JS是解释执行的语言 */
/*定义回调函数 */
function hello(data){
alert(data.name);
}
</script>
3). 将返回值结果 进行特殊格式封装
hello({"id":"1","name":"tom"})
问题: JSONP能否发起POST请求啊?
不能 原因: javaScript中的src属性只能发起get请求,不可以用POST.
2.1.3jQuery中的JSONP
1):编辑页面JS
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONP测试</title>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
alert("测试访问开始!!!!!")
$.ajax({
url:"http://manage.jt.com/web/testJSONP",
type:"get", //jsonp只能支持get请求
dataType:"jsonp", //dataType表示返回值类型 必须添加
jsonp: "callback", //指定参数名称 一般固定写死!!!
jsonpCallback: "hello", //指定回调函数名称
success:function (data){ //data经过jQuery封装返回就是json串
alert(data.id);
alert(data.name);
//转化为字符串使用
//var obj = eval("("+data+")");
//alert(obj.name);
}
});
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
2):京淘后台业务实现
@RestController
public class JSONPController {
@RequestMapping("/web/testJSONP")
public JSONPObject testJSONP(String callback){
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(100L).setItemDesc("详情信息2222");
return new JSONPObject(callback, itemDesc);
}
}
2.2 CORS
2.1.1 CORS介绍
跨源资源共享 (CORS) (或通俗地译为跨域资源共享)是一种基于HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它origin(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的**“预检”**请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。
补充: 现阶段几乎所有的浏览器都默认支持CORS(IE除外)
2.1.2 CORS跨域测试
1).修改ajax请求路径
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
$.get("http://manage.jt.com/testCors",function(data){
alert(data.itemDesc);
})
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
2).跨域报错
2.1.3 ORS跨域原理
说明: CORS 在响应头中标识哪些网址可以访问服务器.CORS的配置是服务器端的配置和浏览器没关系.
2.1.4 编辑后台Controller
package com.jt.web;
import com.jt.pojo.ItemDesc;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(value = "http://www.jt.com") //标识当前Controller中的方法 允许被其他服务器访问
//预检: 在规定时间内同源策略不会再次拦截 提高效率
public class CorsController {
/**
* http://manage.jt.com/testCors
* @return
*/
@RequestMapping("testCors")
public ItemDesc cors(){
return new ItemDesc().setItemDesc("CORS测试");
}
}
响应头信息:
3.nginx反向代理
当你访问baidu.com/api/login的时候,通过在baidu.com的nginx服务器会识别你是api下的资源,会自动代理到api.baidu.com/login,浏览器本身是不知道我实际上是访问的api.baidu.com的数据,和前端资源同源,所以也就不会触发浏览器的同源策略。
4.httpclient没有经过浏览器,没有触发同源策略只算远程访问不算跨域
HttpClient方式(万能的远程调用方式)
导入jar包
<!--添加httpClient jar包 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
编辑入门案例
package com.jt.httpClient;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;
import java.io.IOException;
public class TestHttpClient {
@Test
public void testGet() throws IOException {
//1.实例化对象
HttpClient httpClient = HttpClients.createDefault();
//2.定义请求网址
String url = "http://www.baidu.com"; //html代码
//3.定义请求方式
HttpGet get = new HttpGet(url);
//4.发送请求
HttpResponse httpResponse = httpClient.execute(get);
//5.判断状态码
int status = httpResponse.getStatusLine().getStatusCode();
if(status == 200) {
//6.获取数据
HttpEntity httpEntity = httpResponse.getEntity();
String html = EntityUtils.toString(httpEntity, "UTF-8");
System.out.println(html);
}
}
}