Ajax:跨域 & JSONP

Ajax:跨域 & JSONP


同源与跨域

同源

如果两个页面的协议、域名、端口号都相同,则两个页面同源

例如:

javascript 复制代码
http://www.test.com/index.html

与其同源的网页:

javascript 复制代码
http://www.test.com/other.html
http://www.test.com:80/other.html

注意,如果一个网址没有写:端口号,说明默认端口号为80

不同源的网页:

javascript 复制代码
http://blog.test.com/other.html      // 域名不同
http://www.test.com:8888/other.html  // 端口不同
https://www.test.com/other.html      // 协议不同

注意,httphttps不是一个协议。

同源策略是浏览器提供的一个安全功能,同源策略限制了从同一个源加载的文档或脚本与另一个源的资源交互,这样可以隔离潜在的恶意文件。

JavaScript就是一种脚本,受到同源策略限制,简单来说就是A网站的JavaScript无法与B网站进行交互。

  1. 无法读取非同源页面的cookielocalStorage
  2. 无法接触非同源页面的DOM
  3. 无法向非同源地址发送Ajax请求

跨域

如果两个页面的协议、域名、端口号有任何一项不同,则两个页面跨域

也就是说,同源的对立面就是跨域。

基于同源策略,浏览器会对跨域请求进行拦截,如下图:

浏览器允许用户通过Ajax向跨域的地址发起请求,但是当响应到达浏览器,基于同源策略检测到响应跨域了,那么就会进行拦截,Ajax收不到响应。

为了实现跨域请求,有JSONPCORS两种解决方案。

  • JSONP:兼容性好,兼容低版本IE,只支持GET请求,不支持POST
  • CORS:是跨域请求的根本解决方案,支持GETPOST请求,但是不兼容低版本浏览器

JSONP

JSONP全称Json with Padding,是一种json的使用模式,可以解决主流浏览器的跨域问题。

由于浏览器同源策略的限制,网页中无法通过阿贾克斯请求非同源的接口数据。但是<script>标签不受浏览器同源策略的影响,可以通过src属性,请求非同源的js脚本。

JSONP 的实现原理,就是通过 <script>标签的 src属性,请求跨域的数据接口,并通过函数调用的形式接收跨域接口响应回来的数据。

javascript 复制代码
<script>
  function test(data) {
    console.log(data)
  }
</script>

<script>
  test({ name: '张三', age: 20 })
</script>

以上代码中,定义了两个<script>标签,第一个标签内部实现了test方法,第二个标签内调用了这个方法。由于所有的 <script> 标签共享全局作用域,这是合法的。

假设现在把这个调用的方法放到另一个js文件中./js/test.js

javascript 复制代码
test({ name: 'ls', age: 30 })

./js/test.js文件中,直接调用test方法。

这样可以通过<script src=''>进行引入:

javascript 复制代码
<script>
	function test(data) {
	   console.log(data)
	 }
</script>

<script src="./js/test.js"></script>

这样,当前页面的test方法,就可以被./js/test.js这个文件进行调用。

基于这个策略,可以实现两个服务器之间的JavaScript脚本互相配合,如果想要告诉调用方法的服务器,自己有哪些函数可以调用,可以通过?callback=的方式传递参数:

javascript 复制代码
<script src="./js/test.js?callback=test"></script>

这就是JSONP解决跨域的原理。

测试:

javascript 复制代码
$.ajax({
  method: 'GET',
  url: 'file://D:\code_web\blog\test\test.js',
  success: function (res) {
    console.log(res)
  }
})  

以上代码在test.html中,向file://D:\code_web\blog\test\test.js发起请求,这是一个本地文件路径。为了用户安全考虑,浏览器不允许Ajax直接访问用户主机上的内容,这是基于同源策略实现的。

报错:

其中Cross origin requests表示这是一个跨域请求。

javascript 复制代码
<script>
  function test(data) {
    console.log(data)
  }
</script>

<script src="file://D:\code_web\blog\test\test.js?callback=test"></script>

同样的情况,把test函数定义在test.html中,通过src=属性选择同一主机下的test.js文件。

这次请求成功了,可以看到其发送了一个GET请求,去请求file://D:\code_web\blog\test\test.js这个文件,请求成功后,下方的控制台调用函数,并输出调用结果。

要注意的是,平常要通过<script>引入本地js文件,直接src="路径"就可以了,无需file://这样的协议前缀,这里只是为了测试跨域问题。

可以看出<script>可以实现跨域请求,这也是JSONP实现跨域的方式。


jQuery发送JSONP

使用jQuery发送JSONP请求非常简单,增加一个dataType属性即可:

javascript 复制代码
$(function () {
  $.ajax({
    url: 'https://jsonplaceholder.typicode.com/posts?id=1',
    dataType: 'jsonp',
    success: function (res) {
      console.log(res)
    }
  })
})

如果要发送JSONP请求,填入dataType: 'jsonp',由于JSONP只能使用get,所以也不再需要指定请求的方法为get

发送出去的请求,多出来一个callback=jQuery....参数。这是由jQuery自动生成的,如果通过jQuery发送JSONP请求,其会携带一个callback=jQuery....参数,jQuery....是随机生成的回调函数名称。

jQuery允许用户自己指定这个回调函数的参数:

javascript 复制代码
$.ajax({
  url: 'https://jsonplaceholder.typicode.com/posts?id=1',
  dataType: 'jsonp',
  jsonp: 'call',
  jsonpCallback: 'test',
  success: function (res) {
    console.log(res)
  }
})
  • jsonp:指定回调函数的key
  • jsonpCallback:指定回调函数的value

此时回调函数就变成了call=test,这可以方便后端进行解析。但是一般不会去指定jsonp,直接用默认的callback即可,更多时候只指定回调函数的函数名。

jQuery也是通过<script>标签的src属性实现的跨域访问,但是jQuery会动态创建和移除<script>标签。在发起请求时创建一个<script>,在请求成功后,再移除刚才创建的标签。


相关推荐
F-2H2 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
gqkmiss2 小时前
Chrome 浏览器插件获取网页 iframe 中的 window 对象
前端·chrome·iframe·postmessage·chrome 插件
m0_748247554 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255025 小时前
前端常用算法集合
前端·算法
真的很上进5 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203985 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2345 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1236 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~7 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语7 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js