最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Cloud Gateway調(diào)用Feign異步問題記錄

 更新時(shí)間:2023年04月26日 10:36:15   作者:@Kong  
這篇文章主要介紹了Spring Cloud Gateway調(diào)用Feign異步問題記錄,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

版本設(shè)定 spring cloud 2020.0.2版本

HttpMessageConverters

原因

由于Spring Cloud Gateway 是基于Spring 5、Spring Boot 2.X和Reactor開發(fā)的響應(yīng)式組件,運(yùn)用了大量的異步實(shí)現(xiàn)。

在項(xiàng)目啟動過程中,并不會創(chuàng)建HttpMessageConverters實(shí)例,具體可查看源碼HttpMessageConvertersAutoConfiguration

解決方法

啟動時(shí)創(chuàng)建相應(yīng)的Bean,注入到Spring容器

@Configuration
public class FeignConfig {

    @Bean
    public Decoder decoder(){
        return new ResponseEntityDecoder(new SpringDecoder(feignHttpMessageConverter()));
    }
    private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter(){
        HttpMessageConverters httpMessageConverters=new HttpMessageConverters
                (new MappingJackson2HttpMessageConverter());
        return ()->httpMessageConverters;
    }
}

Filter異步調(diào)用問題

場景

以鑒權(quán)為例,外部訪問經(jīng)由Gateway路由轉(zhuǎn)發(fā),需要驗(yàn)證當(dāng)前請求中是否存在token,可以通過自定義過濾器實(shí)現(xiàn)GlobalFitler實(shí)現(xiàn)。

@PropertySource(value = "classpath:loginfilter.properties")
@Component
public class AuthLoginGlobalFilter implements GlobalFilter, Ordered {
    @Value("#{'/per-user/login,/goods/**'.split(',')}")
    private List<String> ignoreUrls;
    @Autowired
    private IUserFeign userFeign;
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if(ignoreUrls !=null && ignoreUrls.contains(request.getURI().getPath())) {
            return chain.filter(exchange);
        }
        String access_token = request.getHeaders().getFirst("access_token");
        if(StringUtils.isBlank(access_token)) {
            return onError(exchange,"尚未登錄");
        }
        R<String> r = userFeign.validToken(access_token);
        if(r.getCode() == 200) {
            ServerHttpRequest serverHttpRequest = request.mutate().header("uid",r.getData()).build();
            return chain.filter(exchange.mutate().request(serverHttpRequest).build());
        }

        return onError(exchange,r.getMsg());
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private Mono<Void> onError(ServerWebExchange exchange,String msg) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        R r = new R.Builder().buildCustomize(HttpStatus.UNAUTHORIZED.value(),msg);
        ObjectMapper objectMapper = new ObjectMapper();
        String rs = "";
        try {
            rs = objectMapper.writeValueAsString(r);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        DataBuffer dataBuffer =response.bufferFactory().wrap(rs.getBytes());
        return response.writeWith(Flux.just(dataBuffer));
    }
}

R r = userFeign.validToken(access_token);屬于同步調(diào)用,會報(bào)以下錯誤:

錯誤原因

在BlockingSingleSubscriber中會進(jìn)行判斷:

final T blockingGet() {
		if (Schedulers.isInNonBlockingThread()) {
			throw new IllegalStateException("block()/blockFirst()/blockLast() are blocking, which is not supported in thread " + Thread.currentThread().getName());
		}
		if (getCount() != 0) {
			try {
				await();
			}
			catch (InterruptedException ex) {
				dispose();
				throw Exceptions.propagate(ex);
			}
		}

		Throwable e = error;
		if (e != null) {
			RuntimeException re = Exceptions.propagate(e);
			//this is ok, as re is always a new non-singleton instance
			re.addSuppressed(new Exception("#block terminated with an error"));
			throw re;
		}
		return value;
	}

解決方案

解決方案,同步轉(zhuǎn)異步,如果需要獲取返回結(jié)果,可以通過Future方式獲取

@PropertySource(value = "classpath:loginfilter.properties")
@Component
public class AuthLoginGlobalFilter implements GlobalFilter, Ordered {
    @Value("#{'/per-user/login,/goods/**'.split(',')}")
    private List<String> ignoreUrls;
    @Autowired
    private IUserFeign userFeign;
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if(ignoreUrls !=null && ignoreUrls.contains(request.getURI().getPath())) {
            return chain.filter(exchange);
        }
        String access_token = request.getHeaders().getFirst("access_token");
        if(StringUtils.isBlank(access_token)) {
            return onError(exchange,"尚未登錄");
        }
        // WebFlux異步調(diào)用,同步會報(bào)錯
        Future future = executorService.submit((Callable<R>) () -> userFeign.validToken(access_token));
        R<String> r = null;
        try {
            r = (R<String>) future.get();
            if(r.getCode() == 200) {
                ServerHttpRequest serverHttpRequest = request.mutate().header("uid",r.getData()).build();
                return chain.filter(exchange.mutate().request(serverHttpRequest).build());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return onError(exchange,r.getMsg());
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private Mono<Void> onError(ServerWebExchange exchange,String msg) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        R r = new R.Builder().buildCustomize(HttpStatus.UNAUTHORIZED.value(),msg);
        ObjectMapper objectMapper = new ObjectMapper();
        String rs = "";
        try {
            rs = objectMapper.writeValueAsString(r);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        DataBuffer dataBuffer =response.bufferFactory().wrap(rs.getBytes());
        return response.writeWith(Flux.just(dataBuffer));
    }
}

總結(jié)

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 深入解析SpringBatch適配器

    深入解析SpringBatch適配器

    Spring Batch是Spring的一個子項(xiàng)目,使用Java語言并基于Spring框架為基礎(chǔ)開發(fā),使得已經(jīng)使用 Spring 框架的開發(fā)者或者企業(yè)更容易訪問和利用企業(yè)服務(wù),本文給大家介紹SpringBatch適配器的相關(guān)知識,感興趣的朋友一起看看吧
    2021-11-11
  • SpringBoot整合Hmily實(shí)現(xiàn)TCC分布式事務(wù)

    SpringBoot整合Hmily實(shí)現(xiàn)TCC分布式事務(wù)

    這篇文章主要為大家詳細(xì)介紹了SpringBoot如何整合Hmily實(shí)現(xiàn)TCC分布式事務(wù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-11-11
  • Springcloud-nacos實(shí)現(xiàn)配置和注冊中心的方法

    Springcloud-nacos實(shí)現(xiàn)配置和注冊中心的方法

    這篇文章主要介紹了Springcloud-nacos實(shí)現(xiàn)配置和注冊中心的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Spring 加載多個xml配置文件的原理分析

    Spring 加載多個xml配置文件的原理分析

    我們知道Spring一次可以加載多個Bean定義的Xml配置文件,我們可以設(shè)想下如果讓我們來做我們會怎么做?我估計(jì)會根據(jù)配置文件的順序依次讀取并加載,那再來看看Spring是如何做的?
    2021-06-06
  • Apache commons fileupload文件上傳實(shí)例講解

    Apache commons fileupload文件上傳實(shí)例講解

    這篇文章主要為大家詳細(xì)介紹了Apache commons fileupload文件上傳實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Spring中的@PropertySource注解源碼詳細(xì)解析

    Spring中的@PropertySource注解源碼詳細(xì)解析

    這篇文章主要介紹了Spring中的@PropertySource注解源碼詳細(xì)解析,@PropertySource注解,標(biāo)注在配置類@Configuration上面,下面主要分析一下@PropertySource注解的處理過程,也就是怎么把配置信息從.properies文件放到environment中的,需要的朋友可以參考下
    2024-01-01
  • Windows中在IDEA上安裝和使用JetBrains Mono字體的教程

    Windows中在IDEA上安裝和使用JetBrains Mono字體的教程

    這篇文章主要介紹了Windows IDEA上安裝和使用JetBrains Mono字體的教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Java檢查日期字符串是否合法的方法總結(jié)

    Java檢查日期字符串是否合法的方法總結(jié)

    后端接口在接收數(shù)據(jù)的時(shí)候,都需要進(jìn)行檢查。檢查全部通過后,才能夠執(zhí)行業(yè)務(wù)邏輯。本文總結(jié)了四個Java檢查日期字符串是否合法的方法,感興趣的可以了解一下
    2022-10-10
  • Android中Socket通信的實(shí)現(xiàn)方法概述

    Android中Socket通信的實(shí)現(xiàn)方法概述

    這篇文章主要介紹了Android中Socket通信的實(shí)現(xiàn)方法,很有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-08-08
  • java編程中自動拆箱與自動裝箱詳解

    java編程中自動拆箱與自動裝箱詳解

    這篇文章主要介紹了java編程中自動拆箱與自動裝箱詳解,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11

最新評論

二连浩特市| 道真| 介休市| 岢岚县| 奉贤区| 麻阳| 台南市| 荣昌县| 化隆| 方城县| 克东县| 武邑县| 华池县| 汤阴县| 文安县| 海兴县| 寿阳县| 正蓝旗| 连城县| 新沂市| 闻喜县| 喀喇| 固原市| 吉木乃县| 若尔盖县| 临颍县| 马山县| 柳河县| 蒙自县| 临沂市| 木兰县| 美姑县| 彩票| 海南省| 廊坊市| 乡城县| 海淀区| 邓州市| 习水县| 天水市| 上思县|