国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Cloud Gateway如何優(yōu)雅地進行feign調(diào)用

這篇具有很好參考價值的文章主要介紹了Spring Cloud Gateway如何優(yōu)雅地進行feign調(diào)用。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

之前寫過一篇文章,介紹微服務場景下的權(quán)限處理,方案如下:

Spring Cloud Gateway如何優(yōu)雅地進行feign調(diào)用

在實踐中,上面的網(wǎng)關(guān)選型為Spring Cloud Gateway,所以這里就存在一個問題,即網(wǎng)關(guān)如何調(diào)用用戶服務進行鑒權(quán)的問題。

在微服務場景下,服務間的調(diào)用可以通過feign的方式,但這里的問題是,網(wǎng)關(guān)是reactor模式,即異步調(diào)用模式,而feign調(diào)用為同步方式,這里直接通過feign調(diào)用會報錯。

那Spring Cloud Gateway如何優(yōu)雅的進行feign調(diào)用呢,今天的文章帶大家來看下。

1 Spring Cloud Gateway直接進行feign調(diào)用

不做特殊處理,在Spring Cloud Gateway中直接進行feign調(diào)用的代碼如下(這里貼出整個鑒權(quán)的GatewayFilterFactory代碼以方便理解):

@SuppressWarnings("rawtypes")
@Component
@Slf4j
public class ApiAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<ApiAuthGatewayFilterFactory.Config> {

    private static final String USER_HEADER_NAME = "User-Info";

    @Autowired
    private UserClient userClient;

    public ApiAuthGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("checkAuth");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            if (config.checkAuth) {
                String cookie = exchange.getRequest().getHeaders().getFirst("Cookie");
                String url = exchange.getRequest().getPath().toString();
                String httpMethod = exchange.getRequest().getMethodValue();
                // 這里調(diào)用了feign接口,到用戶模塊進行鑒權(quán)
                ResultResponse resultResponse = userClient.checkPermission(url, httpMethod, cookie);
                if (resultResponse.isSuccess()) {
                    // 鑒權(quán)通過,則將用戶信息放入header中,傳到下游服務
                    ServerHttpRequest request = exchange.getRequest().mutate().header(USER_HEADER_NAME, JSON.toJSONString(resultResponse.getData())).build();
                    return chain.filter(exchange.mutate().request(request).build());
                } else {
                    return Mono.defer(() -> {
                        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                        final ServerHttpResponse response = exchange.getResponse();
                        byte[] bytes = JSON.toJSONString(resultResponse).getBytes(StandardCharsets.UTF_8);
                        DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                        return response.writeWith(Flux.just(buffer));
                    });
                }
            } else {
                return chain.filter(exchange);
            }
        };
    }

    @NoArgsConstructor
    @Getter
    @Setter
    @ToString
    public static class Config {
        private boolean checkAuth;
    }
}

不出意外的話,你將會出現(xiàn)如下錯誤:

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3
	at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83)
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	|_ checkpoint ? org.springframework.web.cors.reactive.CorsWebFilter [DefaultWebFilterChain]
	|_ checkpoint ? org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
	|_ checkpoint ? org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
	|_ checkpoint ? HTTP GET "/api/v1/users/getUserInfo" [ExceptionHandlingWebHandler]

上述錯誤則說明了,不能再Spring Cloud Gateway中使用同步調(diào)用,而普通的feign調(diào)用又是同步的,所以會有問題。

2 如何解決Spring Cloud Gateway同步調(diào)用feign問題

一、通過線程池來將feign同步調(diào)用轉(zhuǎn)為異步調(diào)用
在搜索引擎上搜索關(guān)于Spring Cloud Gateway調(diào)用feign的問題,你可能大概率會得到下面的解決方案,及通過將feign同步調(diào)用封裝成異步調(diào)用來解決。

關(guān)鍵代碼如下:

        // 將feign調(diào)用封裝成異步任務,通過線程池的方式提交
        Future<?> future = executorService.submit(() -> {
            userClient.checkPermission(url, httpMethod, cookie);
        });
        try {
            // 通過future方式獲取結(jié)果
            ResultResponse resultResponse = (ResultResponse) future.get();
            if (resultResponse.isSuccess()) {
                ServerHttpRequest request = exchange.getRequest().mutate().header(USER_HEADER_NAME, JSON.toJSONString(resultResponse.getData())).build();
                return chain.filter(exchange.mutate().request(request).build());
            } else {
                return Mono.defer(() -> {
                    exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                    final ServerHttpResponse response = exchange.getResponse();
                    byte[] bytes = JSON.toJSONString(resultResponse).getBytes(StandardCharsets.UTF_8);
                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                    return response.writeWith(Flux.just(buffer));
                });
            }
        } catch (InterruptedException | ExecutionException e) {
            // ignore exception
        }
        // 異常返回
        return Mono.defer(() -> {
                    exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
                    final ServerHttpResponse response = exchange.getResponse();
                    byte[] bytes = JSON.toJSONString("ERROR").getBytes(StandardCharsets.UTF_8);
                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                    return response.writeWith(Flux.just(buffer));
                });

遺憾的是,上述代碼我在調(diào)試的時候雖然能夠解決上面block的報錯,但是并沒有調(diào)通,還是會報錯,初步定位是異步任務調(diào)用獲取返回值的時候有問題,因為此處只是作為一個解決思路展示,而且最終也沒有采用上述方案,就沒有繼續(xù)花時間去解決了。各位如果有解決該問題的歡迎指教。

二、真正的異步調(diào)用——ReactiveFeign
排除方案一的調(diào)試問題,假設方案一可以解決feign同步調(diào)用的問題,那么該方案有什么問題呢?
在我看來方案一的問題有二:一是并不是真正意義上的異步調(diào)用,只不過通過線程池強行提交了feign調(diào)用,而且獲取feign調(diào)用返回結(jié)果的future.get()方法也是同步的;二是此種方式實在算不上優(yōu)雅。

實際上feign無法進行異步調(diào)用的問題,早已被程序員們注意到,并且現(xiàn)在已經(jīng)有了比較成熟的解決方案,即feign-reactive項目,項目地址:GitHub - PlaytikaOSS/feign-reactive。
該項目通過Spring WebClient實現(xiàn)了feign的功能,實現(xiàn)了真正意義上的異步feign調(diào)用。

下面就讓我們通過使用ReactiveFeign來解決Spring Cloud Gateway調(diào)用feign接口的問題,直接看代碼(這里貼出整個鑒權(quán)的GatewayFilterFactory代碼以方便理解):

@Component
@Slf4j
public class ApiAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<ApiAuthGatewayFilterFactory.Config> {

    private static final String USER_HEADER_NAME = "User-Info";

    @Autowired
    private UserReactiveClient userReactiveClient;

    public ApiAuthGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("checkAuth");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            if (config.checkAuth) {
                String cookie = exchange.getRequest().getHeaders().getFirst("Cookie");
                String url = exchange.getRequest().getPath().toString();
                String httpMethod = exchange.getRequest().getMethodValue();
                // ReactiveFeign異步調(diào)用,獲取鑒權(quán)結(jié)果
                return userReactiveClient.checkPermission(url, httpMethod, cookie).flatMap(commonResponse -> {
                    // 鑒權(quán)不通過則返回異常
                    if (!commonResponse.isSuccess()) {
                        return Mono.defer(() -> {
                            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                            final ServerHttpResponse response = exchange.getResponse();
                            byte[] bytes = JSON.toJSONString(commonResponse).getBytes(StandardCharsets.UTF_8);
                            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                            return response.writeWith(Flux.just(buffer));
                        });
                    } else {
                        // 鑒權(quán)通過將用戶信息帶入后端
                        log.info("User-Info: [{}]", JSON.toJSONString(commonResponse.getData()));
                        ServerHttpRequest request = exchange.getRequest().mutate().header(USER_HEADER_NAME, JSON.toJSONString(commonResponse.getData())).build();
                        return chain.filter(exchange.mutate().request(request).build());
                    }
                });
            } else {
                return chain.filter(exchange);
            }
        };
    }

    @NoArgsConstructor
    @Getter
    @Setter
    @ToString
    public static class Config {
        private boolean checkAuth;
    }
}

上述方案,完美解決了Spring Cloud Gateway同步feign調(diào)用的問題,而且看起來也要優(yōu)雅的多,符合異步編程的風格(上述方案的完整代碼,將會在文末給出)。

寫在最后

Spring Cloud Gateway通過WebFlux響應式框架實現(xiàn)了全異步處理,看過Spring Cloud Gateway源碼的同學應該都深有體會,響應式編程的代碼有多么難理解。

正因為Spring Cloud Gateway的響應式編程,導致它直接調(diào)用feign會有問題,因為feign的調(diào)用是同步調(diào)用。

遇到feign同步調(diào)用的問題,直接通過線程池強制將feign調(diào)用轉(zhuǎn)成異步調(diào)用,簡單粗暴,在我看來也并不是一個好的方案。

繼續(xù)深入探究,找到解決feign同步調(diào)用問題的根本解決方案,才是一個合格程序員應該做的事。

通過使用ReactiveFeign,可以優(yōu)雅地解決Spring Cloud Gateway feign同步調(diào)用的問題。

完整示例代碼,請關(guān)注公眾號:WU雙,對話框回復【網(wǎng)關(guān)】即可獲取。

完整示例代碼除了包含網(wǎng)關(guān)的ReactiveFeign異步調(diào)用,還包含了XSS過濾器,緩存請求體等網(wǎng)關(guān)常用功能。文章來源地址http://www.zghlxwxcb.cn/news/detail-478110.html

到了這里,關(guān)于Spring Cloud Gateway如何優(yōu)雅地進行feign調(diào)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • spring cloud整合spring boot,整合nacos、gateway、open-feign等組件

    想看具體詳情的可以看我的github鏈接:codeking01/platform-parent: spring cloud整合spring boot、nacos、gateway、open feign等組件 (github.com) 由于我升級了jdk17,所以用上了spring boot 3.0.2了。 踩坑無數(shù),一堆無用文章,寫來寫去,本文主要是提供給有基礎(chǔ)的開發(fā)者再次快速搭建使用(確定版本

    2024年02月11日
    瀏覽(95)
  • spring cloud gateway k8s優(yōu)雅啟停

    通過配置readiness探針和preStop?hook,實現(xiàn)優(yōu)雅啟動和停止(滾動部署) 1. k8s工作負載配置 2. 網(wǎng)關(guān)改造 經(jīng)過測試發(fā)現(xiàn),可以實現(xiàn)請求0失敗

    2024年03月22日
    瀏覽(16)
  • 【云原生】Spring Cloud Alibaba 之 Feign 遠程調(diào)用 實戰(zhàn)

    【云原生】Spring Cloud Alibaba 之 Feign 遠程調(diào)用 實戰(zhàn)

    在分布式領(lǐng)域中,一個系統(tǒng)由很多服務組成,不同的服務由各自的進程單獨負責。因此,遠程調(diào)用在分布式通信中尤為重要。 遠程調(diào)用可分如下兩類: 本地過程調(diào)用(Local Procedure Call,LPC) ,是指同一臺機器上運行的不同進程之間的互相通信,即在多進程操作系統(tǒng)中,運行

    2023年04月09日
    瀏覽(92)
  • Spring Cloud Alibaba全家桶(四)——微服務調(diào)用組件Feign

    Spring Cloud Alibaba全家桶(四)——微服務調(diào)用組件Feign

    本文小新為大家?guī)?微服務調(diào)用組件Feign 的相關(guān)知識,具體內(nèi)容包含 什么是Feign , Spring Cloud Alibaba快速整合OpenFeign , Spring Cloud Feign的自定義配置及使用 (包括: 日志配置 、 契約配置 、 自定義攔截器實現(xiàn)認證邏輯 、 超時時間配置 、 客戶端組件配置 、 GZIP 壓縮配置 )等

    2024年02月19日
    瀏覽(57)
  • Spring Cloud Gateway:新一代微服務 API 網(wǎng)關(guān),用起來真優(yōu)雅!

    Spring Cloud Gateway:新一代微服務 API 網(wǎng)關(guān),用起來真優(yōu)雅!

    如果沒有網(wǎng)關(guān),難道不行嗎?功能上是可以的,我們直接調(diào)用提供的接口就可以了。那為什么還需要網(wǎng)關(guān)? 因為網(wǎng)關(guān)的作用不僅僅是轉(zhuǎn)發(fā)請求而已。我們可以試想一下,如果需要做一個請求認證功能,我們可以接入到 API 服務中。但是倘若后續(xù)又有服務需要接入,我們又需要

    2024年02月09日
    瀏覽(28)
  • 【Spring Cloud】基于 Feign 實現(xiàn)遠程調(diào)用,深入探索 Feign 的自定義配置、性能優(yōu)化以及最佳實踐方案

    【Spring Cloud】基于 Feign 實現(xiàn)遠程調(diào)用,深入探索 Feign 的自定義配置、性能優(yōu)化以及最佳實踐方案

    在微服務架構(gòu)中,服務之間的通信是至關(guān)重要的,而遠程調(diào)用則成為實現(xiàn)這種通信的一種常見方式。在 Java 中,使用 RestTemplate 是一種傳統(tǒng)的遠程調(diào)用方式,但它存在一些問題,如代碼可讀性差、編程體驗不一致以及參數(shù)復雜URL難以維護等。 在本文中,我們將探討如何通過使

    2024年02月04日
    瀏覽(19)
  • Spring Cloud Feign調(diào)用異常:feign.RetryableException: connect timed out executing POST http://xxx

    本機JUnit單元測試時,調(diào)用部署在開發(fā)環(huán)境(Centos7)的服務時,報feign.RetryableException: connect timed out 直接訪問服務地址時,提示網(wǎng)絡無法訪問 http://192.168.1.15:7002/comDictionary/getDictionaryById?dictionaryId=GIVE_LOGIN 發(fā)現(xiàn)端口沒有打開。需要打開linux防火墻的端口 firewall-cmd --permanent --zon

    2024年03月22日
    瀏覽(22)
  • 【spring Cloud】微服務通信的三種方式RestTemplate、Feign遠程調(diào)用與Dubbo的使用

    目錄 一、通過RestTemplate調(diào)用微服務 二、通過Feign遠程調(diào)用 三、Dubbo? 分布式中的遠程調(diào)用大概分為兩種 RESTful接口? REST,即Representational State Transfer的縮寫,如果一個架構(gòu)符合REST原則,就稱它為RESTful架構(gòu)。 每一個URI代表一種資源; 客戶端和服務器之間,傳遞這種資源的某種

    2024年04月11日
    瀏覽(18)
  • 優(yōu)化 spring cloud gateway+nacos時服務恢復調(diào)用太慢問題

    問題描述 在使用 spring cloud gateway + nacos 做服務發(fā)現(xiàn)時,會發(fā)現(xiàn)當下游的服務器恢復了,但是還有經(jīng)過一段時間 gateway 才成功轉(zhuǎn)發(fā)請求到剛恢復的下游服務上。于是我就深入源碼進行企圖通過修改相關(guān)配置的方式優(yōu)化gateway服務發(fā)現(xiàn)的恢復時間。 相關(guān)依賴版本 源碼 經(jīng)過漫長的

    2024年02月01日
    瀏覽(93)
  • Spring Cloud Gateway集成sentinel進行網(wǎng)關(guān)限流

    本文使用版本如下:

    2024年02月09日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包