20

提供されたオブジェクトのコンテンツに基づいて静的テキストファイルを作成し、ユーザーがダウンロードできるようにしたいと考えています。これが私がやろうとしていたことです:

  1. ユーザーが「エクスポート」を押すと、アプリケーションはMeteor.method()を呼び出し、次に、一般的なノードメソッドを使用してファイルを解析してパブリックディレクトリに書き込みます。

  2. ファイルが作成されたら、からのコールバックでMeteor.method()、生成されたファイルへのリンクを提供します。たとえば、「public / userId/file.txt」です。その後、ユーザーはそのリンクでファイルをダウンロードすることを選択できます。

  3. 次に、Meteor Connect modele(内部で使用)を使用して、上記のURLへのリクエストをファイル自体にルーティングします。userIdとユーザーのログイン状態に基づいていくつかの権限チェックを行うことができます。

問題:静的ファイルがパブリックで生成されると、Webページは毎回自動的にリロードされます。Expressのようなものを使用して、ファイルの作成を処理できるRESTエンドポイントを生成する方が理にかなっているのではないかと思いました。しかし、Meteorセッションデータにアクセスできない場合のアクセス許可の処理方法がわかりません。

ここでの最良の戦略に関するアイデアはありますか?

4

4 に答える 4

24

バージョンでは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();
    }
});

iron:routerを使用する場合

これはサーバー側のルートである必要があります(例:/server/フォルダー内のファイルで定義されています)

編集(2016年5月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流星フォルダを使用しないでください
    • ドットフォルダを使用します(例:隠しフォルダ例.uploads:)

    これらの2つを尊重しないと、以下を使用してmeteorアプリを実行しない限り、アップロードのたびにローカルmeteorが再起動します。meteor run --production

  • 私はこのアプローチを単純な画像のアップロードと提供に使用しました(darioのバージョンに基づく)
  • より複雑なファイル管理が必要な場合は、CollectionFSを検討してください。
于 2013-12-03T18:14:38.213 に答える
16

シンボリックリンクハックは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']));
于 2013-07-27T01:38:01.977 に答える
5

サーバーで生成されたファイルとは対照的に、ユーザーがファイルをアップロードする必要があるという、まったく同じ問題に悩まされていました。同じフォルダレベルで「クライアントパブリックサーバー」の兄弟として「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」フォルダの代わりに「generatedFiles」のようなフォルダがあるかもしれません。サーバーが起動するたびにこれを行う必要があります。これらのフォルダは、サーバーが起動するたびに生成されます。たとえば、実装でファイルが変更されます。

于 2012-11-10T17:41:11.743 に答える
1

もう1つのオプションは、サーバー側のルートを使用してコンテンツを生成し、ダウンロードのためにユーザーのブラウザーに送信することです。たとえば、次のようにIDでユーザーを検索し、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));
    }
});

ただし、この方法には大きな欠点が1つあります。サーバー側のルートは、現在ログインしているユーザーを取得する簡単な方法を提供しません。GitHubでこの問題を参照してください。

于 2014-09-05T00:53:54.397 に答える