【问题标题】:How to add a query parameter for all requests in Spring Webflux如何在 Spring Webflux 中为所有请求添加查询参数
【发布时间】:2021-06-22 16:47:14
【问题描述】:

如何将查询参数放入 spring webflux 中的所有请求中,避免在我打开 http 连接的所有地方重复代码?

我尝试使用过滤器为 WebClient bean 进行配置,该过滤器应该在每次进行 http 调用时在 URL 中放置一个查询参数,但我找不到如何做到这一点的方法。有可能吗?

配置类:

@Configuration
public class IConnectionConfiguration {

    @Value("${api.key}")
    private String apiKey;

    @Value("${api.url}")
    private String url;

    @Bean
    public WebClient webClient(@Autowired ExchangeFilterFunction tokenFilter) {
        return WebClient.builder().baseUrl(url)
                .filters(exchangeFilterFunctions -> {
                    exchangeFilterFunctions.add(tokenFilter);
                })
                .build();
    }

    @Bean
    public ExchangeFilterFunction tokenFilter() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            //todo put token into request as a query param
            return Mono.just(clientRequest);
        });
    }

}

API 调用层:

@Service
public class Client {

    @Autowired
    private WebClient client;

    //todo test method
    public void testConnection() {
        String s = client.get()
                .uri(uriBuilder ->
                        uriBuilder.path("/something/{val}/something")
                              //todo line which I'm trying to avoid
                              //.queryParam("token", "token_value")
                                .build("123-test"))
                .retrieve()
                .bodyToMono(String.class)
                .block();

        System.out.println(s);
    }

}

【问题讨论】:

    标签: java spring spring-webflux


    【解决方案1】:

    我找到了另一种方式,没有自定义 UriBuilderFactory:

            this.client = WebClient.builder().baseUrl(url)
                .filter((request, next) -> {
                    URI reqUri = request.url()
                    URI newUri = new URI(reqUri.getScheme()
                                    , reqUri.getAuthority(), reqUri.getPath()
                                    , reqUri.getQuery() + "&key=${apiKey}"
                                    , null)
                    ClientRequest filtered = ClientRequest.from(request)
                        .url(newUri)
                        .build()
                    next.exchange(filtered)
                }).build();
        }
    

    这是一个时髦的代码,但你明白要点,我敢肯定。

    【讨论】:

    • 忽略最后一个大括号,复制/粘贴错误:-)
    【解决方案2】:

    好像我找到了一个使用 uriBuilderFactory 覆盖的解决方案。

    首先我们需要一个额外的类:

    public class QueryParamsUriBuilderFactory extends DefaultUriBuilderFactory {
    
        private final MultiValueMap<String, String> queryParams;
    
        public QueryParamsUriBuilderFactory(String baseUrl, MultiValueMap<String, String> queryParams) {
            super(baseUrl);
            this.queryParams = queryParams;
        }
    
        @Override
        public UriBuilder builder() {
            return super.builder().queryParams(queryParams);
        }
    
    }
    

    下一步是更新配置:

    @Configuration
    public class IConnectionConfiguration {
    
        @Value("${api.key}")
        private String apiKey;
    
        @Value("${api.url}")
        private String baseUrl;
    
        @Bean
        public WebClient webClient(UriBuilderFactory uriBuilderFactoryWithAuthenticationToken) {
            return WebClient.builder()
                .uriBuilderFactory(uriBuilderFactoryWithAuthenticationToken)
                    .build();
        }
    
        @Bean
        public UriBuilderFactory uriBuilderFactoryWithAuthenticationToken() {
            MultiValueMap<String, String> tokenQueryParam = new LinkedMultiValueMap<>();
            tokenQueryParam.add("token", apiKey);
    
            return new QueryParamsUriBuilderFactory(baseUrl, tokenQueryParam);
        }
    
    }
    

    现在如果我们使用uri(Function&lt;UriBuilder, URI&gt; var1) 函数来设置uri,它将自动添加令牌查询参数。不幸的是,它不适用于 uri(URI var1),但我们可以在新的 QueryParamsUriBuilderFactory 中覆盖所有与 uri 相关的方法,以便为所有可能的 uri 设置方法修复它。

    【讨论】:

      【解决方案3】:

      另一种不需要覆盖或使用过滤器的可能性:将UriComponentsBuilder 与应该用于所有请求的查询参数一起使用。此UriComponentsBuilder 实例可用于为WebClient 实例化DefaultUriBuilderFactory

      根据问题的代码:

      public class IConnectionConfiguration {
      
          private static final String TOKEN_QUERY_PARAMETER = "TOKEN";
      
          @Value("${api.key}")
          private String apiKey;
      
          @Value("${api.url}")
          private String url;
      
          @Bean
          public WebClient webClient() {
              DefaultUriBuilderFactory defaultUriBuilderFactory = new DefaultUriBuilderFactory(uriComponentsBuilder());
              return WebClient.builder()
                      .uriBuilderFactory(defaultUriBuilderFactory)
                      .build();
          }
      
          private UriComponentsBuilder uriComponentsBuilder() {
              return UriComponentsBuilder.fromHttpUrl(url)
                      .queryParam(TOKEN_QUERY_PARAMETER, apiKey);
          }
      
      }
      

      令牌现在将附加到 WebClient 发出的每个请求。

      【讨论】:

        猜你喜欢
        • 2019-02-23
        • 2020-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-20
        • 2021-05-13
        • 1970-01-01
        相关资源
        最近更新 更多