网络请求 | 跨域(待补充)

跨域问题很常见,同时也是面试常问的题目之一,出现的机率super plus【自创词~就是超级多次啦】

跨域问题主要是浏览器的同源策略造成的

因此,本文结构如下:

  1. 什么是同源策略(别说你还不知道URL的组成!)
  2. 如何解决跨域问题?

同源策略

url主要由协议域名端口三部分组成【端口一般是隐藏的~】

同源指的是:协议 域名 端口号 必须一致,其中任意一个不一致就会引起跨域

同源策略限制了从一个源加载的文档或脚本如何与另一个文档进行交互

  • 当前域下的js脚本不能够访问其他域下的cookie localStorage indexDB
  • 当前域下的js脚本不能够操作访问其他域下的DOM
  • 当前域下ajax无法发送跨域请求

同源政策的目的主要是为了保证用户的信息安全,它只是对 js 脚本的一种限制,并不是对浏览器的限制,对于一般的 img、或者script 脚本请求都不会有跨域的限制,这是因为这些操作都不会通过响应结果来进行可能出现安全问题的操作

如何解决跨域问题

解决跨域问题主要有如下几种方式:

  • JSONP:通过动态创建<script>元素并为src属性执行跨域URL实现的【<script><img>类似,能够不受限制地从其他域加载资源】

  • CORSCross-Origin Resource Sharing跨站资源共享,使用自定义的HTTP 头部允许浏览器和服务器相互了解,以确实请求或响应
    应该成功还是失败

1. JSONP

jsonp原理就是利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据

JSONP介绍

  • JSONP

    1
    callback({'name': 'Katrina'});
  • JSONP格式包含两部分:回调和数据

    • 回调是在页面接收到响应之后应该调用的函数,通常回调函数的名称是通过请求来动态指定的
    • 而数据就是作为参数传给回调函数的JSON 数据
  • 典型的JSONP请求

    1
    'http://freegeoip.net/json/?callback=handleResponse'   // handleResponse 回调函数的名称

JSONP实现

  • 实现步骤

    • 准备一个回调函数,用于接收JSON数据
    • 动态创建script标签
    • 给创建的script添加src
    • 把创建好的script添加到head中
  • 原生JS实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 准备一个回调函数,用于接收JSON数据
    function handleResponse(data) {
    console.log(JSON.stringify(data));
    }

    // 动态创建script标签
    let script = document.createElement('script');
    // 给创建的script添加src
    script.src = 'http://www.domain.com:8080/login?username=admin&callback=handleResponse'

    // 把创建好的script添加到head中
    document.head.appendChild(script);

JSONP优缺点

  • 优点:
    • 简单易用
    • 使用JSONP可以直接访问响应,实现浏览器与服务器的双向通信
  • 缺点:
    • 不安全,JSONP 是从不同的域拉取可执行代码,如果这个域并不可信,则可能在响应中加入恶意内容【XSS攻击】
    • 不好缺点JSONP请求是否失败
    • 具有局限性, 仅支持get方法

2. CORS

跨站资源共享(Cross Origin Resource Sharing)使用额外的 HTTP 头来告诉浏览器 :

  • 让运行在一个 origin (domain)上的Web应用被准许访问来自不同源服务器上的指定的资源
  • 当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域HTTP 请求

因此,CORS需要浏览器和服务器同时支持,实现CORS的关键就是服务器,只要服务器实现了CORS请求,就可以跨源通信

请求头头部配置

1
Origin: url;   // url:浏览器url

服务器配置

1
2
3
Access-Control-Allow-Origin: url;  // 允许这个url跨域
// 如果资源公开:
Access-Control-Allow-Origin: *;
  • 如果没有这个头部或者有源但不匹配,则表明不会响应浏览器请求,否则,服务器就会处理这个请求

注意:无论请求还是响应都不会包含cookie信息

在CORS请求中,如果想要传递Cookie,就要满足以下三个条件:

  • 在请求中设置 withCredentials

默认情况下在跨域请求,浏览器是不带 cookie 的,但是我们可以通过设置withCredentials来进行传递 cookie.

1
2
3
4
5
// 原生 xml 的设置方式
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
// axios 设置方式
axios.defaults.withCredentials = true;
  • Access-Control-Allow-Credentials 设置为 true
  • Access-Control-Allow-Origin 设置为 false
  • 跨域XHR 对象允许访问statusstatusText 属性,也允许同步请求
  • 出于安全考虑,跨域XHR对象也施加了一些额外限制
    • 不能使用setRequestHeader()设置自定义头部
    • 不能发送和接收cookie
    • getAllResponseHeaders()方法始终返回空字符串

参考

URL的概念与组成