Как подать файл для URL с заданным префиксом?

Контекст

Я успешно обслуживаю файлы через Vapor (v4):

func configure(_ app: Application) throws {
   // ...
   app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
   // ...
}

Проблема

  • Это пытается сопоставить любой/каждый URL-адрес, который будет соответствовать файлу в publicDirectory.
  • Как можно ограничить «досягаемость» FileMiddleware только запросами, URL-адреса которых имеют определенный префикс? (скажем /files/)

Например, если бы у меня был /Public/foobar.txt, его можно было бы запросить через GET /files/foobar.txt, в то время как GET /foobar.txt НЕ соответствовало бы чему-либо.

Рассмотренные подходы

  • Насколько я понимаю, Middleware применяется ко всему серверу (влияет на каждый «маршрут»), а не к подмножеству... так что это не сработает.
  • Перемещение /Public/foobar.txt в /Public/files/foobar.txt НЕ является решением, поскольку я пытаюсь ограничить URL-адреса, которые потенциально могут быть сопоставлены с файловой системой...
  • Перенаправление GET /files/foobar.txt на GET /foobar.txt также недопустимо. Опять же, мне нужно ограничить потенциальные URL-адреса, которые отображаются в файловой системе.

Вы можете применить промежуточное ПО к подмножеству маршрутов с помощью группы маршрутов. Таким образом, вы можете сделать let filesRoutes = app.grouped("files"), а затем filesRoutes.grouped(FileMiddleware(...))` - если это сработает, хотя я понятия не имею, стоит попробовать!

0xTim 22.12.2020 23:46

@0xTim, я только что попробовал то же самое предложение, но не представляется возможным сгруппировать FileMiddleware так же, как другое промежуточное ПО.

Nick 23.12.2020 00:35
FileMiddleware вещь только для отладки. Вы не должны использовать его для производства. Для производства вы должны настроить nginx для обслуживания ваших статических файлов.
imike 24.12.2020 02:48
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
3
386
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Похоже, что FileMiddleware будет работать только глобально, а не при подключении к группам маршрутов, как это обычно бывает с экземплярами промежуточного программного обеспечения.

Если у вас есть папка с именем Private в папке проекта (т. е. та же папка, в которой находится ваша общая папка), то доступ к содержащимся в ней файлам прост:

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/. Я оставлю вас, чтобы добавить действие, если файл/путь не существует.

Интересный! Разве для этого не потребуется плоская структура каталогов?

user14873944 23.12.2020 05:55

Не уверен в его достоверности, но после многих часов поиска документации я пришел к следующему:

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-адреса (т. Е. Не какого-то мусора «/../../»), я думаю, это должно сработать.

Другие вопросы по теме