SpringBoot
PathVariable
URL Handling
Web Development
Java

PathVariable in SpringBoot with slashes in URL

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

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
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms