A, requirements,

When using Spring Gateway as a gateway, we need to add some public parameters to the requests passing through the gateway that need to be passed to subsequent services. This is where we can use spring Gateway to provide custom request parameters.

Second, to find solutions

1. Refer to official documentation

  • We can guess that Spring Gateway, as a gateway feature, will provide a lot of functionality for handling request parameters, so we queried the documentation and got the following:

2. Explore the implementation rule of GatewayFilterFactory

  • A search of the spring official documentation shows that the Spring Gateway has a lot to offerxxxGatewayFilterFactory, and thesefactoryThey all have the same thingGatewayFilterFactoryAt the end of the.
  • In the class name, we can make a bold guess based on the class name, the first few words describe its function.
  • On the right side of theymlAs can be seen from the configuration file, the configuration of filter also shows certain rules.

3, from the source code to obtain the implementation principle

Now that we are to solve the problem of custom packaging request parameters, then we through the above description rules, can be very bold speculation AddRequestParameteGatewayFilterFactory is the goal we are looking for. So let’s take a look at his source code and see how he does it.

  • Take a look first atAddRequestParameteGatewayFilterFactoryTo get a sense of his composition

In terms of inheritance, it’s still complicated and a little bit confusing, so just go into the code and see what it does.

  • We only paste the core code for analysis, other code temporarily do not care about.
@Override
	public GatewayFilter apply(NameValueConfig config) {
		return new GatewayFilter() {
			@Override
			public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
				URI uri = exchange.getRequest().getURI();
				StringBuilder query = new StringBuilder();
				// GET request parameters from the request URI (GET request parameters are passed by concatenation key=value)
                String originalQuery = uri.getRawQuery(); 
                
				// Determine if the last character is ampersand, if not, concatenate an ampersand for subsequent arguments
				if (StringUtils.hasText(originalQuery)) {
					query.append(originalQuery);
					if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
						query.append('&'); }}// Get the key and value in config and concatenate them to the URI request parameters
				String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
				// TODO urlencode?
				query.append(config.getName());
				query.append('=');
				query.append(value);
				// Put the request parameters back together and pass them into the request to the next request in the filter chain
				try {
					URI newUri = UriComponentsBuilder.fromUri(uri)
							.replaceQuery(query.toString()).build(true).toUri();

					ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri)
							.build();

					return chain.filter(exchange.mutate().request(request).build());
				}
				catch (RuntimeException ex) {
					throw new IllegalStateException(
							"Invalid URI query: \"" + query.toString() + "\" "); }}Copy the code
  • This method is used to encapsulate the concrete implementation of the request parameters, and the concrete implementation steps of the code are explained through comments.

theconfigHow is the key: value passed in?

4. Configure filter and pass parameters

The config parameter is encapsulated in the code implementation. How is this parameter obtained? It’s time to see how the filter is used.

  • As you can see from the figure, our filter is configured and used in this configuration file. So why is there only one in the configuration fileAddRequestParameterConfiguration, rather thanAddRequestParameterGatewayFilterFactory???
  • This is actually a spring convention, implementedGatewayFilterFactoryInterface classes need to be omitted when configured for useGatewayFilterFactory, configure only the prefix.
  • Also, what is red and blue in configuration files?
  • This is the request parameter we need to pass, which is configured as key=red, value=blue.
  • Spring will then help us pass this key value into the apply method’s config above. We can see what it is through the source of config:

As you can see, the implementation of the Config class is a name and value that correspond to two parameters in the configuration file.

Iii. Custom expansion based on official implementation

We see that Spring implements various filters in the same way. But what if none of these satisfy our requirements??

1, custom parameters of the disaster preset

The parameter information we see now is written in the configuration file and cannot be passed dynamic parameters. We can imagine a very common scenario where we need to encapsulate a user’s login information in request parameters for use by other services. How can this be done??

2. Customize by referring to the official implementation

In fact, if we just mimic the official implementation, we can concatenate the dynamic parameters we want to pass to the URI. The concrete implementation is as follows:

  @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                URI uri = exchange.getRequest().getURI();
                StringBuilder query = new StringBuilder();
                String originalQuery = uri.getRawQuery();

                if (StringUtils.hasText(originalQuery)) {
                    query.append(originalQuery);
                    if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
                        query.append('&');
                    }
                }

                String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
                // TODO urlencode?
                query.append(config.getName());
                query.append('=');
                query.append(value);

                // Get the user's cache information in Redis and concatenate it to the request parameters
                String token = exchange.getRequest().getHeaders().getFirst("token");
                if (StringUtils.hasText(token)) {
                    AccountEntity accountEntity = accountAdminApiService.loginAccountAdmin(token);
                    // Get the bean's properties and values via emission for later pass parameter concatenation
                    Map<String, Object> beanMap = beanValue(accountEntity);
                    if(! CollectionUtils.isEmpty(beanMap)) {for (String key : beanMap.keySet()) {
                            query.append('&').append(key).append('=').append(beanMap.get(key)); }}}// This is the same as the official code.
            }

Copy the code
  • After the concatenation of fixed parameter passing, the user login information in the cache can be obtained directly through token, and then the corresponding attributes and values can be concatenated successively.

4. Application of custom filter.

Online read a lot of people write custom, in fact, and this article is similar. But a little did not mention, the definition of how to use ah??

  • By using annotations@beanThe way to configure, specific can be baidu.
  • Here’s a simple configuration to applyymlYou can directly configure rules in the configuration file.
 default-filters:
        - AccountRequestParameter=k, v
Copy the code

Because I’m using it globally, so I’m usingdefault-filtersconfigure

  • It should also be noted that the custom filter will not be loaded by Spring Boot, so an error will be reported at boot time.
  • Solution: Annotate the corresponding class as well@Component, and turn the bean over to Spring to manage.

At this point, we have wrapped the custom request parameters!!