Подтвердить что ты не робот

Создание и обслуживание статических файлов с помощью Meteor

Я ищу для создания статических текстовых файлов, основанных на содержимом поставляемого объекта, который затем может быть загружен пользователем. Вот что я планировал делать:

  • Когда пользователь нажимает "экспорт", приложение вызывает Meteor.method(), который, в свою очередь, анализирует и записывает файл в общий каталог, используя типичные методы Node.

  • После создания файла в обратном вызове от Meteor.method() я предоставляю ссылку на сгенерированный файл. Например, "public/userId/file.txt". Затем пользователь может загрузить файл по этой ссылке.

  • Затем я использую Meteor Connect modele (который он использует внутренне) для маршрутизации любых запросов к указанному выше URL-адресу самому файлу. Я мог бы выполнять некоторые проверки прав на основе userId и зарегистрированного состояния пользователя.

Проблема: когда статические файлы генерируются публично, веб-страница автоматически перезагружается каждый раз. Я подумал, что имеет смысл использовать нечто вроде Express для создания конечной точки REST, которая может иметь дело с созданием файлов. Но тогда я не уверен, как обращаться с разрешениями, если у меня нет доступа к данным сессии Метеор.

Любые идеи о лучшей стратегии здесь?

4b9b3361

Ответ 1

В Meteor (от 0.6.5) перестает работать ссылка на символическую ссылку. Вместо этого я предлагаю создать пакет с похожим кодом для следующего:

packge.js

Package.describe({
  summary: "Application file server."
});

Npm.depends({
  connect: "2.7.10"
});

Package.on_use(function(api) {
  api.use(['webapp', 'routepolicy'], 'server');

  api.add_files([
    'app-file-server.js',
  ], 'server'); 
});

app-file-server.js

var connect = Npm.require('connect');

RoutePolicy.declare('/my-uploaded-content', 'network');

// Listen to incoming http requests
WebApp.connectHandlers
  .use('/my-uploaded-content', connect.static(process.env['APP_DYN_CONTENT_DIR']));

Ответ 2

В версии 0.6.6.3 0.7.x - 1.3.x вы можете сделать следующее:

Чтобы написать

var fs = Npm.require('fs');
var filePath = process.env.PWD + '/.uploads_dir_on_server/' + fileName;
fs.writeFileSync(filePath, data, 'binary');

Чтобы обслуживать

В приложении метеоритного ванили

var fs = Npm.require('fs');
WebApp.connectHandlers.use(function(req, res, next) {
    var re = /^\/uploads_url_prefix\/(.*)$/.exec(req.url);
    if (re !== null) {   // Only handle URLs that start with /uploads_url_prefix/*
        var filePath = process.env.PWD + '/.uploads_dir_on_server/' + re[1];
        var data = fs.readFileSync(filePath);
        res.writeHead(200, {
                'Content-Type': 'image'
            });
        res.write(data);
        res.end();
    } else {  // Other urls will have default behaviors
        next();
    }
});

При использовании железа: маршрутизатор

Это должен быть маршрут на стороне сервера (например: определенный в файле в папке /server/)

Изменить (2016-май-9)

var fs = Npm.require('fs');
Router.route('uploads', {
       name: 'uploads',
       path: /^\/uploads_url_prefix\/(.*)$/,
       where: 'server',
       action: function() {
           var filePath = process.env.PWD + '/.uploads_dir_on_server/' + this.params[0];
           var data = fs.readFileSync(filePath);
           this.response.writeHead(200, {
               'Content-Type': 'image'
           });
           this.response.write(data);
           this.response.end();
       }
    });

Устаревший формат:

Router.map(function() {
    this.route('serverFile', {
        ...// same as object above
    }
});

Примечания

  • process.env.PWD предоставит вам корень проекта
  • если вы планируете размещать файлы внутри своего проекта

    • не используйте папки метеоров public или private
    • используйте точечные папки (например, скрытые папки ex: .uploads)

    Несоблюдение этих двух причин приведет к перезапуску локального метеора при каждой загрузке, если вы не запустите свое приложение для метеорита: meteor run --production

  • Я использовал этот подход для простой загрузки и подачи изображения (на основе dario)
  • Если вы хотите более сложное управление файлами, рассмотрите CollectionFS

Ответ 3

Я застрял в той же самой проблеме, где мне нужно, чтобы пользователи загружали файлы в отличие от файлов, созданных сервером. Я решил это, создав папку "uploads" как родственный для "общего публичного сервера клиента" на том же уровне папки. а затем я создал символьную ссылку на папку ".meteor/local/build/static", например

ln -s ../../../../uploads .meteor/local/build/static/ 

но с файловой системой nodejs api при запуске сервера

Meteor.startup(function () {
    var fs = Npm.require('fs');

    fs.symlinkSync('../../../../uploads', '.meteor/local/build/static/uploads'); 
};

в вашем случае у вас может быть папка типа "сгенерированные файлы" вместо папки "uploads" вам нужно делать это каждый раз, когда сервер запускается, потому что эти папки генерируются каждый раз, когда сервер запускается, например. файл изменяется в вашей реализации.

Ответ 4

Другим вариантом является использование маршрута на стороне сервера для создания контента и отправки его в браузер пользователя для загрузки. Например, следующее будет искать пользователя по идентификатору и возвращать его как JSON. Конечному пользователю предлагается сохранить ответ на файл с именем, указанным в заголовке Content-Disposition. К ответу могут добавляться и другие заголовки, такие как Expires. Если пользователь не существует, возвращается 404.

Router.route("userJson", {
    where: "server",

    path: "/user-json/:userId",

    action: function() {
        var user = Meteor.users.findOne({ _id: this.params.userId });

        if (!user) {
            this.response.writeHead(404);
            this.response.end("User not found");
            return;
        }

        this.response.writeHead(200, {
            "Content-Type": "application/json",
            "Content-Disposition": "attachment; filename=user-" + user._id + ".json"
        });
        this.response.end(JSON.stringify(user));
    }
});

Однако этот метод имеет один большой недостаток. Маршруты на стороне сервера не обеспечивают простой способ получения текущего пользователя. См. эту проблему в GitHub.