欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot解決跨域問題的五種方案

 更新時(shí)間:2024年07月10日 10:29:41   作者:肥肥技術(shù)宅  
跨域問題指的是不同站點(diǎn)之間,使用 ajax 無(wú)法相互調(diào)用的問題,跨域問題本質(zhì)是瀏覽器的一種保護(hù)機(jī)制,它的初衷是為了保證用戶的安全,防止惡意網(wǎng)站竊取數(shù)據(jù),那怎么解決這個(gè)問題呢?接下來(lái)我們一起來(lái)看,需要的朋友可以參考下

跨域問題指的是不同站點(diǎn)之間,使用 ajax 無(wú)法相互調(diào)用的問題。跨域問題本質(zhì)是瀏覽器的一種保護(hù)機(jī)制,它的初衷是為了保證用戶的安全,防止惡意網(wǎng)站竊取數(shù)據(jù)。但這個(gè)保護(hù)機(jī)制也帶來(lái)了新的問題,它的問題是給不同站點(diǎn)之間的正常調(diào)用,也帶來(lái)的阻礙,那怎么解決這個(gè)問題呢?接下來(lái)我們一起來(lái)看。

跨域三種情況

在請(qǐng)求時(shí),如果出現(xiàn)了以下情況中的任意一種,那么它就是跨域請(qǐng)求:

  • 協(xié)議不同,如 http 和 https;
  • 域名不同;
  • 端口不同。

也就是說(shuō),即使域名相同,如果一個(gè)使用的是 http,另一個(gè)使用的是 https,那么它們也屬于跨域訪問。常見的跨域問題如下圖所示:

跨域問題演示

接下來(lái),我們使用兩個(gè) Spring Boot 項(xiàng)目來(lái)演示跨域的問題,其中一個(gè)是端口號(hào)為 8080 的前端項(xiàng)目,另一個(gè)端口號(hào)為 9090 的后端接口項(xiàng)目。

前端網(wǎng)站

前端項(xiàng)目只需要在 resources 下放兩個(gè)文件,一個(gè)用于發(fā)送 ajax 請(qǐng)求的 jquery.js,另一個(gè)是 html 前端頁(yè)面,工程目錄如下圖所示:

其中前端頁(yè)面 index.html 的代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>跨域測(cè)試頁(yè)面</title>
    <script src="js/jquery.min.js"></script>
</head>
<body>
<h1>跨域測(cè)試</h1>
<div>
    <input type="button" onclick="mySubmit()" value=" 發(fā)送跨域請(qǐng)求 ">
</div>
<script>
    function mySubmit() {
        // 發(fā)送跨域請(qǐng)求
        jQuery.ajax({
            url: "http://localhost:9090/test",
            type: "POST",
            data: {"name": "Java"},
            success: function (result) {
                alert("返回?cái)?shù)據(jù):" + result.data);
            }
        });
    }
</script>
</body>
</html>

后端接口

后端接口項(xiàng)目首先先在 application.properties 配置文件中,設(shè)置項(xiàng)目的端口號(hào)為 9090,如下所示:

server.port=9090

然后創(chuàng)建一個(gè)后端控制器,返回一個(gè) JSON 格式的數(shù)據(jù),實(shí)現(xiàn)代碼如下:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
 
@RestController
public class TestController {
    @RequestMapping("/test")
    public HashMap<String, Object> test() {
        return new HashMap<String, Object>() {{
            put("state", 200);
            put("data", "success");
            put("msg", "");
        }};
    }
}

以上兩個(gè)項(xiàng)目創(chuàng)建并啟動(dòng)成功之后,使用前端項(xiàng)目訪問后端接口,因?yàn)槎丝诓灰粯?,所以也屬于跨域訪問,運(yùn)行結(jié)果如下圖所示:

解決跨域問題

在 Spring  Boot 中跨域問題有很多種解決方案,比如以下 5 個(gè):

  • 使用 @CrossOrigin 注解實(shí)現(xiàn)跨域;
  • 通過配置文件實(shí)現(xiàn)跨域;
  • 通過 CorsFilter 對(duì)象實(shí)現(xiàn)跨域;
  • 通過 Response 對(duì)象實(shí)現(xiàn)跨域;
  • 通過實(shí)現(xiàn) ResponseBodyAdvice 實(shí)現(xiàn)跨域。

當(dāng)然如果你愿意的話,還可以使用過濾器來(lái)實(shí)現(xiàn)跨域,但它的實(shí)現(xiàn)和第 5 種實(shí)現(xiàn)類似,所以本文就不贅述了。

解決方案1:通過注解跨域

使用 @CrossOrigin 注解可以輕松的實(shí)現(xiàn)跨域,此注解既可以修飾類,也可以修飾方法。當(dāng)修飾類時(shí),表示此類中的所有接口都可以跨域;當(dāng)修飾方法時(shí),表示此方法可以跨域,它的實(shí)現(xiàn)如下:

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
 
@RestController
@CrossOrigin(origins = "*")
public class TestController {
    @RequestMapping("/test")
    public HashMap<String, Object> test() {
        return new HashMap<String, Object>() {{
            put("state", 200);
            put("data", "success");
            put("msg", "");
        }};
    }
}

以上代碼的執(zhí)行結(jié)果如下圖所示:

從上圖中可以看出,前端項(xiàng)目訪問另一個(gè)后端項(xiàng)目成功了,也就說(shuō)明它解決了跨域問題。優(yōu)缺點(diǎn)分析此方式雖然雖然實(shí)現(xiàn)(跨域)比較簡(jiǎn)單,但細(xì)心的朋友也能發(fā)現(xiàn),使用此方式只能實(shí)現(xiàn)局部跨域,當(dāng)一個(gè)項(xiàng)目中存在多個(gè)類的話,使用此方式就會(huì)比較麻煩(需要給所有類上都添加此注解)。

解決方案2:通過配置文件跨域

接下來(lái)我們通過設(shè)置配置文件的方式就可以實(shí)現(xiàn)全局跨域了,它的實(shí)現(xiàn)步驟如下:

  • 創(chuàng)建一個(gè)新配置文件;
  • 添加 @Configuration 注解,實(shí)現(xiàn) WebMvcConfigurer 接口;
  • 重寫 addCorsMappings 方法,設(shè)置允許跨域的代碼。

具體實(shí)現(xiàn)代碼如下:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
@Configuration // 一定不要忽略此注解
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 所有接口
                .allowCredentials(true) // 是否發(fā)送 Cookie
                .allowedOriginPatterns("*") // 支持域
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"}) // 支持方法
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

解決方案3:通過 CorsFilter 跨域

此實(shí)現(xiàn)方式和上一種實(shí)現(xiàn)方式類似,它也可以實(shí)現(xiàn)全局跨域,它的具體實(shí)現(xiàn)代碼如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
 
@Configuration // 一定不能忽略此注解
public class MyCorsFilter {
    @Bean
    public CorsFilter corsFilter() {
        // 1.創(chuàng)建 CORS 配置對(duì)象
        CorsConfiguration config = new CorsConfiguration();
        // 支持域
        config.addAllowedOriginPattern("*");
        // 是否發(fā)送 Cookie
        config.setAllowCredentials(true);
        // 支持請(qǐng)求方式
        config.addAllowedMethod("*");
        // 允許的原始請(qǐng)求頭部信息
        config.addAllowedHeader("*");
        // 暴露的頭部信息
        config.addExposedHeader("*");
        // 2.添加地址映射
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", config);
        // 3.返回 CorsFilter 對(duì)象
        return new CorsFilter(corsConfigurationSource);
    }
}

解決方案4:通過 Response 跨域

此方式是解決跨域問題最原始的方式,但它可以支持任意的 Spring Boot 版本(早期的 Spring Boot 版本也是支持的)。但此方式也是局部跨域,它應(yīng)用的范圍最小,設(shè)置的是方法級(jí)別的跨域,它的具體實(shí)現(xiàn)代碼如下:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
 
@RestController
public class TestController {
    @RequestMapping("/test")
    public HashMap<String, Object> test(HttpServletResponse response) {
        // 設(shè)置跨域
        response.setHeader("Access-Control-Allow-Origin", "*");
        return new HashMap<String, Object>() {{
            put("state", 200);
            put("data", "success");
            put("msg", "");
        }};
    }
}

解決方案5:ResponseBodyAdvice

通過重寫 ResponseBodyAdvice 接口中的 beforeBodyWrite(返回之前重寫)方法,我們可以對(duì)所有的接口進(jìn)行跨域設(shè)置,它的具體實(shí)現(xiàn)代碼如下:

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
 
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    /**
     * 內(nèi)容是否需要重寫(通過此方法可以選擇性部分控制器和方法進(jìn)行重寫)
     * 返回 true 表示重寫
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }
    /**
     * 方法返回之前調(diào)用此方法
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request,
                                  ServerHttpResponse response) {
        // 設(shè)置跨域
        response.getHeaders().set("Access-Control-Allow-Origin", "*");
        return body;
    }
}

此實(shí)現(xiàn)方式也是全局跨域,它對(duì)整個(gè)項(xiàng)目中的所有接口有效。

原理分析

為什么通過以上方法設(shè)置之后,就可以實(shí)現(xiàn)不同項(xiàng)目之間的正常交互呢?這個(gè)問題的答案也很簡(jiǎn)單,我們之前在說(shuō)跨域時(shí)講到:“跨域問題本質(zhì)是瀏覽器的行為,它的初衷是為了保證用戶的訪問安全,防止惡意網(wǎng)站竊取數(shù)據(jù)”,那想要解決跨域問題就變得很簡(jiǎn)單了,只需要告訴瀏覽器這是一個(gè)安全的請(qǐng)求,“我是自己人”就行了,那怎么告訴瀏覽器這是一個(gè)正常的請(qǐng)求呢?只需要在返回頭中設(shè)置“Access-Control-Allow-Origin”參數(shù)即可解決跨域問題,此參數(shù)就是用來(lái)表示允許跨域訪問的原始域名的,當(dāng)設(shè)置為“*”時(shí),表示允許所有站點(diǎn)跨域訪問,如下圖所示:

所以以上 5 種解決跨域問題的本質(zhì)都是給響應(yīng)頭中加了一個(gè) Access-Control-Allow-Origin 的響應(yīng)頭而已。

總結(jié)

跨域問題的本質(zhì)是瀏覽器為了保證用戶的一種安全攔截機(jī)制,想要解決跨域問題,只需要告訴瀏覽器“我是自己人,不要攔我”就行。它的常見實(shí)現(xiàn)方式有 5 種:通過注解實(shí)現(xiàn)局部跨域、通過配置文件實(shí)現(xiàn)全局跨域、通過 CorsFilter 對(duì)象實(shí)現(xiàn)全局跨域、通過 Response 對(duì)象實(shí)現(xiàn)局部跨域,通過 ResponseBodyAdvice 實(shí)現(xiàn)全局跨域。

以上就是SpringBoot解決跨域問題的五種方案的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot解決跨域的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中如何獲取時(shí)間戳的方法實(shí)例

    java中如何獲取時(shí)間戳的方法實(shí)例

    時(shí)間戳通常是一個(gè)字符序列,唯一地標(biāo)識(shí)某一刻的時(shí)間,所以下面這篇文章主要給大家介紹了關(guān)于java中如何獲取時(shí)間戳的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • SpringBoot使用Spark過程詳解

    SpringBoot使用Spark過程詳解

    這篇文章主要介紹SpringBoot使用Spark的方法的相關(guān)知識(shí),小編通過實(shí)際案例向大家展示操作過程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望能幫助大家解決問題
    2023-02-02
  • JavaWeb response和request對(duì)象原理及實(shí)例解析

    JavaWeb response和request對(duì)象原理及實(shí)例解析

    這篇文章主要介紹了JavaWeb response和request對(duì)象原理及實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • RabbitMQ中的Channel和Exchange詳解

    RabbitMQ中的Channel和Exchange詳解

    這篇文章主要介紹了RabbitMQ中的Channel和Exchange詳解,創(chuàng)建和銷毀TCP連接很耗時(shí),打開太多TCP連接,耗操作系統(tǒng)資源,并發(fā)量大到一定程度,系統(tǒng)的吞吐量會(huì)降低,使用一個(gè)connection多channel的方式,可以提升連接的利用率,需要的朋友可以參考下
    2023-08-08
  • SpringBoot+redis配置及測(cè)試的方法

    SpringBoot+redis配置及測(cè)試的方法

    這篇文章主要介紹了SpringBoot+redis配置及測(cè)試的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • JAVA中AES加密方法實(shí)例分析

    JAVA中AES加密方法實(shí)例分析

    這篇文章主要介紹了JAVA中AES加密方法,實(shí)例分析了java中AES加密與解密的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • MyBatis測(cè)試報(bào)錯(cuò):Cannot?determine?value?type?from?string?'xxx'的解決辦法

    MyBatis測(cè)試報(bào)錯(cuò):Cannot?determine?value?type?from?string?&a

    這篇文章主要給大家介紹了關(guān)于MyBatis測(cè)試報(bào)錯(cuò):Cannot?determine?value?type?from?string?'xxx'的解決辦法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • Java8新特性 StreamAPI實(shí)例詳解

    Java8新特性 StreamAPI實(shí)例詳解

    這篇文章主要為大家介紹了Java8新特性 StreamAPI實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Windows?10卸載JDK1.8超詳細(xì)圖文教程

    Windows?10卸載JDK1.8超詳細(xì)圖文教程

    這篇文章主要介紹了Windows?10卸載JDK1.8超詳細(xì)圖文教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • Gradle的SpringBoot項(xiàng)目構(gòu)建圖解

    Gradle的SpringBoot項(xiàng)目構(gòu)建圖解

    這篇文章主要介紹了Gradle的SpringBoot項(xiàng)目構(gòu)建圖解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評(píng)論