0%

跨域

跨域

默认不同源地址之间不能发送请求, 只有同源的地址才可以相互通过 AJAX 的方式请求

  • 什么是不同源

    • 协议不同端口号不同域名不同, 都叫不同源
  • 跨域和 AJAX 没有关系

    • 跨域是通过 script 标签发送请求
    • AJAX 是通过 xhr 对象来发送请求
  • 解决方案

    • 现代化的 Web 应用中肯定会有不同源的现象,所以必然要解决这个问题,从而实现跨域请求

CORS

Cross Origin Resource Share 跨域资源共享

  • 跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器让运行在一个 origin (domain) 上的Web 应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求

  • 跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 XMLHttpRequestFetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险

  • 跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源

  • 只需要在后台中 设置响应头来允许跨域请求, 客户端无需作出变化 (依然通过 ajax 处理请求)

    1
    2
    // Node.js 作服务端
    res.header('Access-Control-Allow-Origin', '*')
    1
    2
    3
    4
    // php 作服务端
    <? php
    header('Access-Control-Allow-Origin: *')

    1
    2
    3
    4
    // 客户端
    $.get('http://locolhost/cors.php', {}, function (res) {
    console.log(res)
    })

JSONP

JSON with Padding,是一种 借助于 script 标签发送跨域请求 的技巧

  • 原理

    • 在客户端借助 script 标签请求服务端的一个地址,服务端返回一段带有函数调用的 JavaScript 函数调用的脚本,将原本需要返回给客户端的数据传递进去, 返回给客户端
  • 为什么不用 img / a / link?

    • img —— 可以发送请求, 但不能返回响应结果
    • link —— 可以返回响应结果, 但是无法处理相应结果
  • 以后绝大多数情况都是采用 JSONP 的手段完成不同源地址之间的跨域请求

    1
    2
    <!-- 客户端 -->
    <script src="http://api.zce.me/users.php?callback=foo"></script>
    1
    2
    // 服务端返回
    foo(['我', '是', '你', '原', '本', '需', '要', '的', '数', '据'])
  • 总结

    • 由于 XMLHttpRequest 无法发送不同源地址之间的跨域请求,所以我们必须要另寻他法,script 这种方案就是我们最终选择的方式,我们把这种方式称之为 JSONP

JSONP 的封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<script>
function jsonp(option) {
// 要通过 query 传参给服务端的函数名
var callbackName = 'getData_' + Date.now() + Math.random().toString().substr(2, 5)

// 处理 url
if (typeof (option.data) === 'object') {
var arr = []
for (const key in option.data) {
arr.push(key + '=' + option.data[key])
}
option.data = arr.join('&')
}

var script = document.createElement('script')
// jsonp 只能发送 get 请求
script.src = option.url + '?' + option.data + '&callback=' + callbackName

// script 只有挂载到页面中才会发送请求
document.body.appendChild(script)

// 声明处理响应结果的全局函数
window[callbackName] = function (res) {
option.success(res)

// 拿到数据后, 去掉页面上生成的 script
document.body.removeChild(script)
// 拿到数据后, 去掉 window 上挂载的回调函数
delete window[callbackName]
}
}

// 函数调用
jsonp({
url: 'http://localhost:80/cate',
data: { id: 1 },
success: function (data) {
console.log(data)
}
})
</script>

JSONP 的问题

JSONP 需要服务端配合,服务端按照客户端的要求返回一段 JavaScript 调用客户端的函数的字符串

  • 只能发送 GET 请求
  • ⚠️ JSONP 用的是 script 标签,跟 AJAX 提供的 XMLHttpRequest 没有任何关系!!!

jQuery 中使用 JSONP

jQuery 中使用 JSONP 就是将 dataType 设置为 jsonp

1
2
3
4
5
6
7
$.ajax({
url: 'http://localhost/jsonp/server.php',
dataType: 'jsonp',
success: function (res) {
console.log(res)
}
})

相关库

jsonp