ajax
ajax全称Asynchronous JavaScript and XML(异步的JavaScript与XML),是网页无需刷新页面、使用js与服务器进行交互的一种技术。
ajax的基本流程可以概括为:页面上js脚本实例化一个XMLHttpRequest对象,设置好服务器端的url、必要的查询参数、回调函数之后,向服务器发出请求,
服务器在处理请求之后将处理结果返回给页面,触发事先绑定的回调函数。
这样,页面脚本如果想要改变一个区域的内容,只需要通过ajax向服务器获取与该区域有关的少量数据,在回调函数中将该区域的内容替换掉即可,不需要刷新整个页面。
XMLHttpRequest在发送请求的时候,有两种方式:同步与异步。
同步方式是请求发出后,一直到收到服务器返回的数据为止,浏览器进程被阻塞,页面上什么事也做不了。
而异步方式则不会阻塞浏览器进程,在服务端返回数据并触发回调函数之前,用户依然可以在该页面上进行其他操作。
ajax的核心是异步方式,而同步方式只有在极其特殊的情况下才会被用到。
XMLHttpRequest 对象是一个接口,用于创建一个http请求对象实例,打开一个URL,然后发送这个请求,
当传输完毕后,结果的HTTP状态以及返回的响应内容也可以从请求对象中获取
五种状态
0:未打开
1:未发送
2:以获取响应头
3:正在下载响应体
4:请求完成
XMLHttpRequest API
1 | const xhr = new XMLHttpRequest() |
使用ajax 封装POST,GET请求
1 | function Ajax(method,url,callback,data,async){ |
同源策略
为了保证用户信息的安全,防止恶意的网站窃取数据
解决办法:同源策略
同源策略是指三个相同:协议相同,域名相同,端口相同
以上三个不相同则是非同源,非同源之间相互访问即跨域访问
跨域和ip没有关系
跨域
浏览器在阻止跨域,阻止方式可能是在一开始就限制了发起跨站的请求,也可能是跨站请求可以正常发起,但返回结果被浏览器拦截了
为什么要防止跨域
跨域访问时会受到同源策略的三个限制
1、Cookie、LocalStorage 和 IndexDB 无法读取。
通过浏览器document.cookie我们可以获取用户登录态,如果cookie可以读取的话,
就会出现在A公司网站里可以去B公司网站获取登录信息的事情,这样就容易将用户信息泄露
2、DOM 无法获得
如果DOM可以获得,现在我是一个假网站,利用iframe套嵌一个目前线上运营的电商网站,那么
消费者在输入支付密码时,那我就可以获取input的值,从而获取用户支付密码
3、AJAX 请求不能发送
如果AJAx可以发送的话,那我们就能将内网东西下载下来发送到外网服务器,从而造成内网信息泄露
如何实现跨域
jsonp
原理是利用<script>标签可以在任何域下获取资源的原理,将要跨域获取的接口url放在<script>标签的src里面,
然后js将标签放到body里面,其中url包含一个callback参数,用于指向处理response的函数,这个函数我们挂载的window上,
即我们在js中定义的的函数
如果在浏览器直接访问接口’http://x.com:7001/json?callback=xxx'
页面会显示
1 | /**/ typeof xxx === 'function' && xxx({"msg":"hello world"}); |
就是说,在请求这个接口时,会去window上找xxx这个对象,看它是不是函数,如果是函数,
就将接口定义的response({“msg”:”hello world”})作为参数传递给xxx函数,并执行xxx函数
1 | //json 接口 服务端 |
现在访问http://y.com/x.html,在浏览器console就会打印{"msg":"hello world”}
CORS
XMLHttpRequest 2.0以后可以使用cors方法进行跨域
CORS需要浏览器和服务器同时支持
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。
对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。
浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
1 | //cors接口 服务端 |
Access-Control-Allow-Origin 的属性值只允许设置为单个确定域名字符串或者 (),设置的话,最不安全,允许所有域可以访问
在服务器端设置CORS跨域请求中的多域名白名单,可以实现Access-Control-Allow-Origin 允许对某一个或几个网站开放跨域请求权限
原理就是在服务器端判断请求的Header中Origin属性值(req.header.origin)是否在我们的域名白名单列表内。
如果在白名单列表内,那么我们就把 Access-Control-Allow-Origin 设置成当前的Origin值,这样就满足了Access-Control-Allow-Origin 的单一域名要求,也能确保当前请求通过访问;如果不在白名单列表内,则返回错误信息。
1 | // 判断origin是否在域名白名单列表中 |
与JSONP的比较:
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
iframe-Hash
Location 对象是 Window 对象的一个部分,可通过 window.location 属性来访问
hash是location对象的的一个属性,可以设置或返回从井号 (#) 开始的 URL(锚)
iframe是HTML标签,作用是文档中的文档,或者浮动的框架(FRAME)。iframe元素会创建包含另外一个文档的内联框架(即行内框架)。
原理是在原域页面包装 跨域src的iframe标签,在跨域src的文件里请求跨域的资源(此时二者同域),
跨域src文件是可以获取到iframe父类,即我们原域的window对象,
通过改变原域的hash值,引发原域onhashchange,从而将资源带回到原域
1 | //原域js |
iframe-window.name
原理是利用iframe的window.name,name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)
1 | //原域js |
iframe-postMessage
利用HTML5的postMessage方法
1 | //原域js |
小结
跨域方法很多
选择如何使用可以考虑以下几方面
1.场景,选择简单的
2.安全,解决问题是否足够安全
3.数据来源,如果跨域接口可以传资源给原域,则可以使用iframe代理
4.承接第三种情景,如果接口不允许传资源,则只能寄希望于后台,使用反向代理的方法获取