作者 | 浪里行舟
责编 | 胡巍巍
前后端数据交互经常会碰到请求跨域,什么是跨域,以及有哪几种跨域方式,这正是本文要探讨的内容 。
什么是跨域?
1.什么是同源策略及其限制内容?
同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击 。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个IP地址,也非同源 。
文章插图
同源策略限制内容有:
- Cookie、LocalStorage、IndexedDB 等存储性内容
- DOM 节点
- AJAX 请求发送后,结果被浏览器拦截了
- <imgsrc=https://www.isolves.com/it/cxkf/bk/2019-07-01/XXX>
- <linkhref=https://www.isolves.com/it/cxkf/bk/2019-07-01/XXX>
- <scriptsrc=https://www.isolves.com/it/cxkf/bk/2019-07-01/XXX>
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域 。不同域之间相互请求资源,就算作“跨域” 。常见跨域场景如下图所示:
文章插图
特别说明两点:
第一:如果是协议和端口造成的跨域问题“前台”是无能为力的 。
第二:在跨域问题上,仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断 。“URL的首部”可以理解为“协议, 域名和端口必须匹配” 。
这里你或许有个疑问:请求跨域了,那么请求到底发出去没有?
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了 。
你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会?
因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应 。但是表单并不会获取新的内容,所以可以发起跨域请求 。
同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了 。
跨域解决方案
1.jsonp
1) JSONP原理
利用 <script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据 。JSONP请求一定需要对方的服务器做支持才可以 。
2) JSONP和AJAX对比
JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式 。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
3) JSONP优缺点
JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题 。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击 。
4) JSONP的实现流程
- 声明一个回调函数,其函数名(如show)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data) 。
- 创建一个 <script>标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址中向服务器传递该函数名(可以通过问号传参:?callback=show) 。
- 服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是show,它准备好的数据是 show('我不爱你') 。
- 最后服务器把准备的数据通过HTTP协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作 。
// index.htmlfunction jsonp({ url, params, callback }) { return new Promise((resolve, reject) => { let script = document.createElement('script') window[callback] = function(data) { resolve(data) document.body.removeChild(script) } params = { ...params, callback } // wd=b&callback=show let arrs = [] for (let key in params) { arrs.push(`${key}=${params[key]}`) } script.src = https://www.isolves.com/it/cxkf/bk/2019-07-01/`${url}?${arrs.join('&')}` document.body.AppendChild(script) })}jsonp({ url: 'http://localhost:3000/say', params: { wd: 'Iloveyou' }, callback: 'show'}).then(data => { console.log(data)})上面这段代码相当于向 http://localhost:3000/say?wd=Iloveyou&callback=show这个地址请求数据,然后后台返回 show('我不爱你'),最后会运行show()这个函数,打印出'我不爱你' 。
推荐阅读
- 加入抖音mcn机构需要多少粉丝 抖音十大mcn机构的联系方式
- 思维方式决定人生高度
- 抖音的物流配送方式 抖音上物流信息怎么看
- 滇红茶正确冲泡方式
- 抖音不只是卖货,还有其他的五大变现方式
- 2022年新浪微博让红包飞怎么领取红包,微博红包获得方式有哪些
- 古丈毛尖冲泡方式及问题
- 近代饮茶方式及功夫茶艺
- 白茶的冲泡方式,你知道哪些?
- 有一种营销方式 公司产品的营销方式