spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

Gateway MVC forward request but with decoded parameters (%2B becomes +)

Open lohoso opened this issue 1 year ago • 1 comments

Describe the bug I use the following version of Spring Cloud Gateway MVC to forward request. org.springframework.cloud spring-cloud-starter-gateway-mvc 4.1.2

same description as https://github.com/spring-cloud/spring-cloud-gateway/issues/3272 a bug in the code of the ProxyExchangeHandlerFunction class.

	boolean encoded = containsEncodedQuery(serverRequest.uri());
	// @formatter:off
	URI url = UriComponentsBuilder.fromUri(serverRequest.uri())
			.scheme(uri.getScheme())
			.host(uri.getHost())
			.port(uri.getPort())
			.replaceQueryParams(serverRequest.params())
			.build(encoded)
			.toUri();

This is based on serverRequest.uri() to determine whether the URL has been encoded, but when constructing a new URL, the query parameter is replaced with serverRequest.params(). The reality is that serverRequest.uri() is encoded by the URI, but serverRequest.params() is not encoded.

Sample The url as http://localhost:8083/test?q=name%3Atestname%2BState%3AFailed In Gateway MVC will forward the rquest as http://localhost:8083/test?q=name:testname+State:Failed, when the corrsponding service receive the request, then + becomes space character.

For the UriComponentsBuilder, it will use HierarchicalUriComponents internally, is this related to below issue? https://github.com/spring-projects/spring-framework/issues/23025

lohoso avatar Apr 10 '24 09:04 lohoso

containsEncodedQuery can also cause double-encoding. If the (decoded!) query param contains a non-standard char, it will assume everything is not encoded and encode the whole thing again.

rworsnop avatar Sep 18 '24 19:09 rworsnop

Is there any news on this one? I'm using spring boot 3.3.6 with spring-cloud-gateway-server-mvc 4.1.6 (based on spring-cloud-dependencies 2023.0.5)

I faced the same issue where my parameter filters=%5B%5D is forwarded to the downstream service with filters=[] which lead to 400 from the downstream service.

The definition of the route is quite simple:

// Assure service is a variable with service name while url is the downstream service url

route(service.toLowerCase())
                    .add(RouterFunctions.route(RequestPredicates.all().and(path(service.toLowerCase() + "/**")), http(url.toString())))
                    .filter(stripPrefix(1))
                    .build()

When debugging, it look like this reply point the root cause, but I still have it in spring-cloud 4.1.6

Is there, at least, any workaround?


I'm a bit confused that such basic core feature of a gateway seems to not work when migrate to the new version. I already faced this issue, which has been solved since (I copy the fix in a new stripPrefix)

Nhoutain avatar Mar 19 '25 23:03 Nhoutain

This is still bug in 4.2.x

cuizhanming avatar May 13 '25 13:05 cuizhanming

Seems like this might be a duplicate of https://github.com/spring-cloud/spring-cloud-gateway/issues/3759. There is a PR to fix this https://github.com/spring-cloud/spring-cloud-gateway/pull/3789

ryanjbaxter avatar May 13 '25 14:05 ryanjbaxter