跨域問題:CORS解決跨域原理


1.什么是跨域問題?如圖

1.1跨域問題需要滿足以下條件

1.1.1 跨域

域名不同,域名相同,端口不同或者二級域名不同

1.1.2 是針對ajax的一種限制

跨域問題是瀏覽器對於ajax請求的一種安全限制:一個頁面發起的ajax請求,只能是於當前頁同域名的路徑,這能有效的阻止跨站攻擊

2.怎么解決跨域問題

2.1目前比較常用的跨域解決方案有3種:

  • Jsonp

    最早的解決方案,利用script標簽可以跨域的原理實現。

    限制:

    • 需要服務的支持

    • 只能發起GET請求

  • nginx反向代理

    思路是:利用nginx反向代理把跨域為不跨域,支持各種請求方式

    缺點:需要在nginx進行額外配置,語義不清晰

  • CORS

    規范化的跨域請求解決方案,安全可靠。

    優勢:

    • 在服務端進行控制是否允許跨域,可自定義規則

    • 支持各種請求方式

3.CORS解決跨域

3.1什么是CORS

3.1.1CORS允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制

  • 瀏覽器端:

    目前,所有瀏覽器都支持該功能(IE10以下不行)。整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。

  • 服務端:

    CORS通信與AJAX沒有任何差別,因此你不需要改變以前的業務邏輯。只不過,瀏覽器在請求中攜帶一些頭信息,我們需要以此判斷是否允許其跨域,然后在響應頭中加入一些信息即可。這一般通過過濾器完成即可。

 3.2實現原理

 瀏覽器會將ajax請求分為兩類,其處理方案略有差異:簡單請求特殊請求

3.1簡單請求 =>(請求方法:HEAD、GET、POST)

3.1.1解決:在請求頭中攜帶一個字段:Origin

Origin中會指出當前請求屬於哪個域(協議+域名+端口)。服務會根據這個值決定是否允許其跨域

如果服務器允許跨域,需要在返回的響應頭中攜帶下面信息:

Access-Control-Allow-Origin: 允許跨域的域名
Access-Control-Allow-Credentials: true

3.2特殊請求=>(不符合簡單請求的會被瀏覽器判定為特殊請求,,例如請求方式為PUT)

如果是特殊請求產生的跨域會先發起一次OPTIONS預檢請求,如果預檢請求通過了,才會發送真正的請求。

特殊請求會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。

瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP動詞和頭信息字段。只有得到肯定答復,瀏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。

與簡單請求相比,除了Origin以外,多了兩個頭:

Access-Control-Request-Method:接下來會用到的請求方式,比如PUT

Access-Control-Request-Headers:會額外用到的頭信息

4.CORS解決跨域方式

4.1方式一:只需要在controller類上添加注解@CrossOrigin 即可!這個注解其實是CORS的實現(這個一般不會采用,麻煩,每個控制器都得加)

 

 4.2方式二:在攔截器配置(推薦)

package cn.mindgd.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //表示接受任意域名的請求,也可以指定域名
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));

        //該字段可選,是個布爾值,表示是否可以攜帶cookie
        response.setHeader("Access-Control-Allow-Credentials", "true");

        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");

        response.setHeader("Access-Control-Allow-Headers", "*");

return true; } }
package cn.mindgd.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 攔截器配置
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {


    @Bean
    AuthInterceptor corsInterceptor() {
        return new AuthInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
         * 攔截全部路徑,這個跨域需要放在最上面
         */
        registry.addInterceptor(corsInterceptor()).addPathPatterns("/**");

        WebMvcConfigurer.super.addInterceptors(registry);

    }

}

4.3方式三:在網關解決,SpringCloudGateway是Spring官方出品

只需要在application.yml文件中配置一下就可以解決跨域問題:

spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins:
              - "www.xxx.com" #允許跨域的域名
            allowedHeaders:
              - "*"
            allowCredentials: true
            maxAge: 360000
            allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTIONS
              - HEAD

 

想看更多精彩內容,可以關注我的CSDN

我的CSDN


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM