Skip to main content

Command Palette

Search for a command to run...

Techniques to Handle Redirect URLs with Trailing Slashes in Spring Cloud Gateway — Explained with Real Java Example

Imagine this: you deploy a Spring Cloud Gateway in front of multiple microservices. Everything runs smoothly — until one day, users start reporting that /login redirects to /login/ endlessly, or worse, returns a 404. What happened?The problem isn...

Published
4 min read
Techniques to Handle Redirect URLs with Trailing Slashes in Spring Cloud Gateway — Explained with Real Java Example
T

I am Tuanh.net. As of 2024, I have accumulated 8 years of experience in backend programming. I am delighted to connect and share my knowledge with everyone.

1. The Subtle Problem Behind Trailing Slashes

Spring Cloud Gateway, much like NGINX or any modern reverse proxy, treats URLs with and without trailing slashes as distinct paths.

  • /login/login/
  • /api/v1/users/api/v1/users/

That small difference can create redirect loops or broken URLs if your redirect rules don’t normalize both cases.

How Spring Cloud Gateway Processes URLs InternallyWhen a request comes in, the RouteLocator in Spring Cloud Gateway evaluates the path predicates sequentially.Each Predicate (like Path=/login/**) matches exactly the given structure — meaning /login may match but /login/ may not.

Additionally, if you perform a redirect in a filter (for example using SetStatusGatewayFilterFactory or RedirectToGatewayFilterFactory), the resulting Location header might contain or lack the trailing /, depending on how you’ve defined it.This inconsistency triggers client-side confusion and sometimes double redirects.

2. The Correct Way to Handle Redirect URLs with Trailing Slashes

Normalize Paths in a Custom Gateway Filter

The most reliable solution is to write a custom filter that ensures all incoming requests are normalized — for example, removing trailing slashes except for the root /.

Here’s a full example:

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class TrailingSlashNormalizerFilter implements GatewayFilter, Ordered {

@Override
public Mono<void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String rawPath = exchange.getRequest().getURI().getPath();

if (rawPath.length() > 1 && rawPath.endsWith("/")) {
String newPath = rawPath.substring(0, rawPath.length() - 1);
exchange = exchange.mutate()
.request(exchange.getRequest().mutate()
.path(newPath)
.build())
.build();
}

return chain.filter(exchange);
}

@Override
public int getOrder() {
return -100; // Run early before route matching
}
}
</void>

Explanation:

  • The filter checks if the request path ends with /.
  • It trims the trailing slash but skips the root /.
  • The exchange.mutate() call rebuilds the request before routing continues.
  • Setting order to -100 ensures it runs before route predicates.

This guarantees that both /login and /login/ resolve to the same target route without needing messy rewrite rules.

Using Built-In RewritePath Filter (Declarative YAML Style)

If you prefer a declarative approach, you can use the RewritePath filter in application.yml:

spring:
cloud:
gateway:
routes:
- id: login-service
uri: http://localhost:8081
predicates:
- Path=/login/**, /login
filters:
- RewritePath=/login(?<segment>/?)$, /login
</segment>

How it works:

  • The regular expression (? /?) captures the optional trailing slash.
  • The replacement /login ensures a consistent form before redirecting to the target service.

This way, /login and /login/ behave identically from the client’s perspective.

RedirectTo Filter — Be Explicit with the Slash

If you are performing a manual redirect:

filters:
- name: RedirectTo
args:
status: 302
url: https://example.com/login/

Always decide one canonical form — either always with or always without a trailing slash — and keep it consistent across all redirects.The golden rule is: redirect only once.If you see two redirects in your browser’s network tab (301 → 302 → final), you’ve got a mismatch between your filter and your service URL definitions.

3. Broader Considerations

SEO and Caching ImplicationsFrom an SEO perspective, /docs and /docs/ are seen as two distinct URLs.If you’re using Spring Cloud Gateway in front of a static docs site (like Swagger UI or a React SPA), inconsistent slashes can lead to duplicate content penalties.Normalize them early at the gateway level to ensure consistent canonical URLs.

Performance and Load ImpactRedirect loops aren’t just annoying — they waste CPU cycles.Each unnecessary redirect adds at least one extra HTTP round trip, increasing latency and backend load.A single gateway-level fix (like the custom filter above) can save hundreds of wasted requests in high-traffic systems.

4. Key Takeaways

Normalize Early, Redirect OnceWhether using code or YAML, ensure the request path has a single canonical form before hitting downstream services.

Keep Redirect URLs ConsistentIf you choose to end URLs with /, apply that rule globally. Don’t mix conventions across microservices.

Test All Edge CasesTest with and without slashes using tools like Postman or cURL:

curl -I http://localhost:8080/login
curl -I http://localhost:8080/login/

Both should return the same final location without loops.

5. Conclusion

Trailing slashes might look harmless, but in distributed architectures like Spring Cloud Gateway, they can cause chaos in routing and redirects.By normalizing paths via custom filters or RewritePath, and being consistent with redirect targets, you ensure smoother routing, cleaner SEO, and fewer headaches at 2 a.m.

Want to dive deeper into how Spring Cloud Gateway handles URI mutation and routing filters internally?💬 Ask your question in the comments below — let’s dissect it together!

Read more at : Techniques to Handle Redirect URLs with Trailing Slashes in Spring Cloud Gateway — Explained with Real Java Example

More from this blog

T

tuanh.net

540 posts

Are you ready to elevate your Java, OOP, Spring, and DevOps skills? Look no further!