SpringBoot
PathVariable
URL Handling
Web Development
Java

PathVariable in SpringBoot with slashes in URL

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Spring Boot's @PathVariable extracts values from URL path segments, but it breaks when the value itself contains slashes (/). By default, Spring treats each / as a path segment delimiter, so a path variable value like folder/subfolder/file.txt is split across multiple segments instead of being captured as one variable. To handle slashes in path variables, use a regex pattern in the mapping ({path:.+}), use /** with HandlerMethodArgumentResolver, or encode the slashes as %2F.

The Problem

java
1@GetMapping("/files/{filename}")
2public String getFile(@PathVariable String filename) {
3    return "File: " + filename;
4}
5
6// GET /files/report.pdf → filename = "report.pdf" ✓
7// GET /files/docs/report.pdf → 404 Not Found ✗

/files/docs/report.pdf does not match /files/{filename} because Spring sees docs and report.pdf as separate path segments.

Fix 1: Regex Pattern {variable:.+}

java
1@GetMapping("/files/{filename:.+}")
2public String getFile(@PathVariable String filename) {
3    return "File: " + filename;
4}
5
6// GET /files/report.pdf → filename = "report.pdf" ✓
7// But: GET /files/docs/report.pdf → still 404 ✗

The .+ regex matches one or more characters including dots, but does not match across / boundaries. This only fixes the problem where Spring strips the file extension (suffix pattern matching), not the slash problem.

Fix 2: Catch-All with /**

java
1@GetMapping("/files/**")
2public String getFile(HttpServletRequest request) {
3    String fullPath = request.getRequestURI();
4    String basePath = "/files/";
5    String filename = fullPath.substring(fullPath.indexOf(basePath) + basePath.length());
6    return "File: " + filename;
7}
8
9// GET /files/docs/report.pdf → filename = "docs/report.pdf" ✓
10// GET /files/a/b/c/file.txt → filename = "a/b/c/file.txt" ✓

Use AntPathMatcher for cleaner extraction:

java
1@GetMapping("/files/**")
2public String getFile(HttpServletRequest request) {
3    String pattern = (String) request.getAttribute(
4        HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
5    String path = (String) request.getAttribute(
6        HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
7
8    String filename = new AntPathMatcher().extractPathWithinPattern(pattern, path);
9    return "File: " + filename;
10}

Fix 3: URL-Encode the Slashes

Encode / as %2F in the client request:

java
1@GetMapping("/files/{filename}")
2public String getFile(@PathVariable String filename) {
3    // filename is automatically URL-decoded
4    return "File: " + filename;
5}
6
7// Client sends: GET /files/docs%2Freport.pdf
8// filename = "docs/report.pdf" ✓

However, many web servers (Tomcat, Apache) reject %2F in path segments by default for security reasons. You must configure the server to allow it:

properties
# application.properties
server.tomcat.relaxed-path-chars=|,{,},[,]
java
1// Or programmatically
2@Bean
3public WebServerFactoryCustomizer<TomcatServletWebServerFactoryCustomizer> tomcatCustomizer() {
4    return factory -> factory.addConnectorCustomizers(connector -> {
5        connector.setEncodedSolidusHandling("passthrough");
6    });
7}

Fix 4: Use a Request Parameter Instead

Avoid slashes in path variables entirely by using a query parameter:

java
1@GetMapping("/files")
2public String getFile(@RequestParam String path) {
3    return "File: " + path;
4}
5
6// GET /files?path=docs/report.pdf → path = "docs/report.pdf" ✓
7// GET /files?path=a/b/c/file.txt → path = "a/b/c/file.txt" ✓

This is the simplest and most portable solution. Query parameters are not split by /.

Fix 5: Base64 Encode the Path

java
1@GetMapping("/files/{encodedPath}")
2public String getFile(@PathVariable String encodedPath) {
3    String path = new String(Base64.getUrlDecoder().decode(encodedPath));
4    return "File: " + path;
5}
6
7// Client encodes: Base64("docs/report.pdf") = "ZG9jcy9yZXBvcnQucGRm"
8// GET /files/ZG9jcy9yZXBvcnQucGRm → path = "docs/report.pdf" ✓

Use URL-safe Base64 encoding to avoid + and / characters in the encoded output.

Spring Boot 3 / WebFlux

In Spring WebFlux (reactive), the same issue exists:

java
1@GetMapping("/files/**")
2public Mono<String> getFile(ServerHttpRequest request) {
3    String path = request.getPath().pathWithinApplication().value();
4    String filename = path.replaceFirst("/files/", "");
5    return Mono.just("File: " + filename);
6}

Common Pitfalls

  • Assuming {variable:.+} captures slashes: The .+ regex in @PathVariable matches any character except /. It only prevents Spring from stripping the file extension (e.g., .json). It does not capture path segments separated by slashes.
  • Forgetting that Tomcat blocks %2F by default: Even if you URL-encode slashes as %2F, Tomcat rejects them with a 400 error for security (path traversal prevention). You must explicitly configure encodedSolidusHandling to allow them.
  • Using request.getRequestURI() without decoding: getRequestURI() returns the raw (encoded) URI. If the path contains %20 or other encoded characters, you must decode them. Use URLDecoder.decode(uri, StandardCharsets.UTF_8) or Spring's HandlerMapping attributes.
  • Not handling trailing slashes: /files/docs/ and /files/docs may resolve differently. Spring Boot 3 no longer matches trailing slashes by default. Configure PathPatternParser to enable trailing slash matching if needed.
  • Security risk with path traversal: Accepting arbitrary paths in URLs opens the door to path traversal attacks (../../etc/passwd). Always validate and sanitize the extracted path before using it to access files. Use Path.normalize() and verify the resolved path stays within the allowed directory.

Summary

  • @PathVariable does not capture slashes — Spring splits on / before matching
  • Use /** with manual path extraction for the most reliable approach
  • Use query parameters (@RequestParam) to avoid the problem entirely
  • URL-encoding slashes as %2F requires server configuration (Tomcat blocks it by default)
  • Always validate extracted paths to prevent path traversal attacks
  • In Spring Boot 3, trailing slash matching is disabled by default — configure explicitly if needed

Course illustration
Course illustration

All Rights Reserved.