如何使用给定前缀为 URL 提供文件?
How to serve file for URL with a given prefix?
上下文
我一直在通过 Vapor (v4) 成功提供文件:
func configure(_ app: Application) throws {
// ...
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
// ...
}
问题
- 这会尝试映射 any/every URL 以匹配 publicDirectory 中的文件。
- 如何将
FileMiddleware
的“范围”限制为仅 URL 具有特定前缀的请求? (说 /files/
)
例如,如果我有 /Public/foobar.txt
,人们会通过 GET /files/foobar.txt
请求它,而 GET /foobar.txt
不会匹配任何东西。
考虑过的方法
- 我的理解是
Middleware
在服务器范围内应用(影响每个“路由”)而不是子集...所以这行不通。
- 将
/Public/foobar.txt
移动到 /Public/files/foobar.txt
不是解决方案,因为我试图限制可能映射到文件系统的 URLs...
- 将
GET /files/foobar.txt
重定向到 GET /foobar.txt
也是不可接受的。同样,我需要限制映射到文件系统的潜在 URLs。
似乎 FileMiddleware
只能在全局范围内工作,而不是像中间件实例通常那样附加到路由组时。
如果您在项目文件夹中有一个名为 Private 的文件夹(即与您的 Public 文件夹相同的文件夹),那么访问其中包含的文件非常简单:
public func configure(_ app: Application) throws {
app.get("files", "**") { req -> Response in
let filepath = req.parameters.getCatchall()
let workPath = DirectoryConfiguration.detect().workingDirectory
var fileURL = URL(fileURLWithPath: workPath)
.appendingPathComponent("Private", isDirectory: true)
.appendingPathComponent(filepath.joined(separator: "/"), isDirectory: false)
return req.fileio.streamFile(at: fileURL.path)
}
}
假设您是 运行 localhost:8080
上的这个最小项目,它将通过 URL:
提供文件
http://localhost:8080/files/path/to/myFile.txt
编辑
OP 仅表示平面文件。根据评论,使其可以在 Private/
下使用任意路径。如果 file/path 不存在,我会让你添加操作。
不确定它的有效性,但在搜索了多个小时的文档后我想到了以下内容:
app.get("files", "**") { req - > Response in
// get rest of URL directly from `req.url.path`
// ensure clean/secure URL and map it to file path using `DirectoryConfiguration`
req.fileio.streamFile(at: "/path/to/files")
}
除了确保 URL 干净(即不是一些“/../../”垃圾)的一些安全问题外,我认为应该这样做。
上下文
我一直在通过 Vapor (v4) 成功提供文件:
func configure(_ app: Application) throws {
// ...
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
// ...
}
问题
- 这会尝试映射 any/every URL 以匹配 publicDirectory 中的文件。
- 如何将
FileMiddleware
的“范围”限制为仅 URL 具有特定前缀的请求? (说/files/
)
例如,如果我有 /Public/foobar.txt
,人们会通过 GET /files/foobar.txt
请求它,而 GET /foobar.txt
不会匹配任何东西。
考虑过的方法
- 我的理解是
Middleware
在服务器范围内应用(影响每个“路由”)而不是子集...所以这行不通。 - 将
/Public/foobar.txt
移动到/Public/files/foobar.txt
不是解决方案,因为我试图限制可能映射到文件系统的 URLs... - 将
GET /files/foobar.txt
重定向到GET /foobar.txt
也是不可接受的。同样,我需要限制映射到文件系统的潜在 URLs。
似乎 FileMiddleware
只能在全局范围内工作,而不是像中间件实例通常那样附加到路由组时。
如果您在项目文件夹中有一个名为 Private 的文件夹(即与您的 Public 文件夹相同的文件夹),那么访问其中包含的文件非常简单:
public func configure(_ app: Application) throws {
app.get("files", "**") { req -> Response in
let filepath = req.parameters.getCatchall()
let workPath = DirectoryConfiguration.detect().workingDirectory
var fileURL = URL(fileURLWithPath: workPath)
.appendingPathComponent("Private", isDirectory: true)
.appendingPathComponent(filepath.joined(separator: "/"), isDirectory: false)
return req.fileio.streamFile(at: fileURL.path)
}
}
假设您是 运行 localhost:8080
上的这个最小项目,它将通过 URL:
http://localhost:8080/files/path/to/myFile.txt
编辑
OP 仅表示平面文件。根据评论,使其可以在 Private/
下使用任意路径。如果 file/path 不存在,我会让你添加操作。
不确定它的有效性,但在搜索了多个小时的文档后我想到了以下内容:
app.get("files", "**") { req - > Response in
// get rest of URL directly from `req.url.path`
// ensure clean/secure URL and map it to file path using `DirectoryConfiguration`
req.fileio.streamFile(at: "/path/to/files")
}
除了确保 URL 干净(即不是一些“/../../”垃圾)的一些安全问题外,我认为应该这样做。