如何使用Ratpack实现类似Apache的动态目录列表?
Hey there! Nice to see you experimenting with Ratpack. The bad news is that Ratpack's built-in files handler doesn't include a native dynamic directory listing feature like Apache does out of the box. The good news is it's super easy to add this functionality with a custom handler—let me walk you through it.
The Approach
We'll add a top-level handler that checks if the requested path points to a directory (that doesn't have an index.html file). If it does, we'll generate a simple HTML directory listing on the fly. If not, we'll pass the request along to the existing files handler so it can serve static files or index pages as usual.
Full Working Code
Here's how to modify your script to add directory listing:
#!/usr/bin/env groovy @Grab('io.ratpack:ratpack-groovy:1.5.1') import static ratpack.groovy.Groovy.ratpack import java.net.URLEncoder ratpack { handlers { // Custom handler for directory listings all { ctx -> def requestPath = ctx.request.path // Only process paths that end with a slash (likely directory requests) if (requestPath.endsWith('/')) { def targetDir = ctx.fileSystemBinding.file(requestPath) // Check if the path exists and is a directory if (targetDir.exists() && targetDir.isDirectory()) { // Check if an index file exists—if so, let the files handler serve it def indexFile = targetDir.resolve("index.html") if (!indexFile.exists()) { // Generate directory listing HTML def listingHtml = new StringBuilder() listingHtml.append(""" <html> <head> <title>Directory: ${requestPath}</title> <style> body { font-family: Arial, sans-serif; margin: 2rem; } h1 { color: #2c3e50; } ul { list-style-type: none; padding-left: 0; } li { margin: 0.5rem 0; } a { text-decoration: none; color: #3498db; } a:hover { text-decoration: underline; } .dir { font-weight: bold; } </style> </head> <body> """) listingHtml.append("<h1>Directory Listing: ${requestPath}</h1>") listingHtml.append("<ul>") // Add link to parent directory (if not at root) if (!requestPath.equals('/')) { def parentPath = requestPath.substring(0, requestPath.lastIndexOf('/')) ?: '/' listingHtml.append("<li><a href=\"${parentPath}\">.. (Parent Directory)</a></li>") } // Sort files alphabetically (case-insensitive) and list them targetDir.listFiles().sort { a, b -> a.name.compareToIgnoreCase(b.name) }.each { file -> def encodedFileName = URLEncoder.encode(file.name, 'UTF-8') def fileUrl = requestPath + encodedFileName + (file.isDirectory() ? '/' : '') def fileClass = file.isDirectory() ? "class='dir'" : "" listingHtml.append(""" <li> <a href="${fileUrl}" ${fileClass}>${file.name}</a> ${file.isDirectory() ? '/' : ""} </li> """) } listingHtml.append("</ul></body></html>") // Send the generated HTML response ctx.response.contentType("text/html") ctx.render(listingHtml.toString()) return // Stop processing further handlers } } } // If we get here, pass the request to the next handler (files) ctx.next() } // Your original static files handler files { dir "static" index // Still serves index.html when present } } }
Key Details Explained
- Handler Order: The custom
allhandler runs first, so it can intercept directory requests before thefileshandler takes over. - Index File Priority: We check for an
index.htmlfirst—if it exists, we let thefileshandler serve it just like before. - Clean HTML & Styling: I added basic CSS to make the listing look nicer, but you can tweak this to match your needs.
- URL Encoding: We use
URLEncoderto handle filenames with spaces or special characters correctly. - Sorting: Files are sorted alphabetically (case-insensitive) for a more user-friendly listing.
How to Use It
- Save this script (e.g.,
ratpack-server.groovy) - Create a
staticdirectory in the same folder - Add some files/subdirectories to
static - Run the script with
groovy ratpack-server.groovy - Visit
http://localhost:5050/in your browser—you'll see the directory listing if there's noindex.htmlpresent.
内容的提问来源于stack exchange,提问作者wu-lee

