HTTP跨域请求 | 青训营

117 阅读4分钟

请求分类

简单请求

简单请求具有以下特点:

  1. 请求方法只能是GET/HEAD/POST​中的一种

  2. 请求头部只能是简单请求头如:

    Accept/Accept-language/Content-Language/Content-Type

    DPR/Downlink/Save-Data/Viewport-Width/Width

  3. 请求中任何XMLHtttpRequestUpload​对象均没有注册任何事件监听器

  4. 请求中没有使用ReadableStream​对象

  5. 请求中没有使用FormData​对象

  6. 请求头部Content-Type​的值仅限于下面三者之一:

    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  7. 简单请求会自动在头部添加一个orign​字段,用于表明请求的来源

    如果服务器允许改来源的请求,会在响应头部添加Access-Control-Allow-Origin​字段以允许跨域请求

复杂请求

复杂请求具有以下特点:

  1. 使用复杂的请求方法如PUT/DELET​等

  2. 在实际请求中使用了自定义的请求头

  3. 请求中的Content-Type​不属于简单请求中允许的三种之一

  4. 使用了ReadableStream​对象来读取请求体的数据

  5. 相比于简单请求,复杂请求需要先进行预检请求,然后再发送实际请求:

    • 在实际发送请求前先发送一个预检请求以获取服务器是否允许跨域请求的信息,预检请求使用的HTTP方法是**OPTIONS**,并带有特殊的头部信息如Access-Control-Request-Headers​用来说明请求中将会使用的头部和方法
    • 服务器在接收到预检请求后,如果允许跨域请求,则会在响应中添加Access-Control-Allow-Origin​等字段,表明允许该来源的实际请求

处理策略

浏览器处于安全考虑实施同源策略,限制了跨域请求的执行,以防止潜在的安全漏洞。对于跨域请求,主要由以下几种处理方法:

  1. CORS - Cross-Origin Resource Sharing

    该策略的目标是允许服务器指定哪些源被授权访问其资源,从而解除浏览器的同源策略限制;

    CORS策略的主要实现步骤:

    • 使用JS发起跨域请求时,浏览器会自动发送一个简单请求或预检请求;

    • 服务器收到请求后根据请求的源,检查是否允许该源进行跨域访问;若服务器允许跨域访问,会在响应头中添加相应的CORS头;

    • 常用的CORS头有以下几种:

      • Access-Control-Allow-Origin​:指定允许访问该资源的域,可以是单个域名或者 *​(表示允许任意域名访问);
      • Access-Control-Allow-Methods​:指定允许的 HTTP 方法;
      • Access-Control-Allow-Headers​:指定允许的自定义请求头;
      • Access-Control-Allow-Credentials​:指定是否允许发送身份凭证(例如 Cookie/Authorization​ 头);
      • Access-Control-Expose-Headers​:指定哪些响应头可以被暴露给客户端。
    • 浏览器收到包含合适CORS头的响应,就会允许前端访问该跨域资源;若没有得到正确的CORS头,就阻止前端访问该资源,保持同源策略。

  2. 代理 - Proxy

    在浏览器和服务器之间设置一个代理服务器作为中间人,浏览器将请求发送给代理服务器,代理服务器再将请求转发给目标服务器,并将目标服务器的响应返回给浏览器;

    通常浏览器执行的请求和代理服务器是同源的,因此不会触发跨域安全机制。

  3. Iframe

    随着技术的发展,Iframe相比于过去使用的场景减少了,而使用具有更高安全性和性能的CORS、WebSocket等技术。

    • Iframe允许在一个页面中嵌套另一个页面,即称为Iframe,并在Iframe中加载页面,这两个页面的源可以不同;
    • Iframe提供了子页面和父页面进行通信的方法,如通过Window​对象、使用postMessage​方法等,这样父子页面之间可以在不同源之间传递数据,而不会触犯同源策略的限制。
  4. JSONP - JSON with Padding

    利用<script>​标签进行跨域请求的技术,直接绕过了浏览器的同源策略:

    • <script>​标签中创建一个回调函数,用于处理服务器返回的数据:

      <script>
        function handleData(data) {
          // 在这里处理从服务器返回的数据
          console.log(data);
        }
      </script>
      
    • 构造一个包含回调函数名的URL,将这个URL作为<script>​标签的src​属性值:

      即告诉够酸服务器要调用名为handleData​的回调函数,并将数据作为参数传递回来

      <script src="https://domainB.com/api/data?callback=handleData"></script>
      
    • 浏览器加载该标签时,会向src​中的url发送GET​请求,服务器收到请求后将要返回的数据包裹在回调函数中:

      handleData({"name": "John", "age": 30});
      
    • 这样,浏览器会正常加载该脚本并通过回调函数处理返回的JSON数据。

  5. WebSocket

    WebSocket实际不能解决跨域问题,因为该技术本身是不受同源策略限制的,它允许跨域通信,可以在任何域之间建立连接。

    WebScoket具有以下特点:

    • 客户端和服务器之间的连接会保持打开状态,允许在同一个连接上交换数据,减少建立连接的开销;
    • 允许客户端和服务器之间同时发送和接收数据,实现双向通信;
    • 建立一次连接后,数据可以直接传输,不需要频繁的握手过程,具有较低的通信延迟;
    • 使用二进制帧来传输数据,相比传统的文本数据格式,可以减少数据传输量,提高传输效率。