Je cherche à créer des fichiers texte statiques en fonction du contenu d'un objet fourni, qui peut ensuite être téléchargé par l'utilisateur. Voici ce que je prévoyais faire:
Lorsque l'utilisateur frappe 'exporter', l'application appelle un Meteor.method()
qui, à son tour, analyse et écrit le fichier dans le répertoire public en utilisant des méthodes de nœud typiques.
Une fois le fichier créé, dans le rappel de Meteor.method()
je fournit un lien vers le fichier généré. Par exemple, 'public / userId / file.txt'. L'utilisateur peut alors choisir de télécharger le fichier sur ce lien.
J'utilise ensuite Meteor's Connect modele
(qu'il utilise en interne) pour acheminer toutes les requêtes vers l'URL ci-dessus vers le fichier lui-même. Je pourrais faire des vérifications d'autorisations en fonction de l'utilisateur et de l'état connecté de l'utilisateur.
Le problème: lorsque les fichiers statiques sont générés en public, la page Web se recharge automatiquement à chaque fois. Je pensais qu'il serait plus logique d'utiliser quelque chose comme Express pour générer un point final REST, qui pourrait traiter la création des fichiers. Mais je ne suis pas sûr de savoir comment traiter les autorisations si je n'ai pas accès aux données de la session Meteor.
Des idées sur la meilleure stratégie ici?
Le lien symbolique ne fonctionnera plus dans Meteor (à partir de 0.6.5). Au lieu de cela, je suggère de créer un package avec un code similaire à celui-ci:
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']));
En version 0.6.6.3 0.7.x – 1.3.x vous pouvez faire ce qui suit:
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(); } });
Il doit s'agir d'une route côté serveur (ex: définie dans un fichier dans /server/
folder)
Modifier (2016-mai-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(); } });
Format dépassé:
Router.map(function() { this.route('serverFile', { ...// same as object above } });
process.env.PWD
vous donnera la racine du projet Si vous prévoyez de mettre des fichiers dans votre projet
public
ou private
.uploads
) Ne pas respecter ces deux causes provoqueront des météorites locaux à recommencer à chaque téléchargement, sauf si vous exécutez votre application de météorite avec: production de meteor run --production
J'ai été coincé au même problème, où j'ai besoin que les utilisateurs téléchargent des fichiers en contraste avec vos fichiers générés par le serveur. Je l'ai résolu en créant un dossier "uploads" en tant que frère et sœur au "serveur public client" sur le même niveau de dossier. Et puis j'ai créé un lien simbolique vers le dossier '.meteor / local / build / static' comme
ln -s ../../../../uploads .meteor/local/build/static/
Mais avec le système de fichiers nodejs api à l'heure de début du serveur
Meteor.startup(function () { var fs = Npm.require('fs'); fs.symlinkSync('../../../../uploads', '.meteor/local/build/static/uploads'); };
Dans votre cas, vous pouvez avoir un dossier comme "fichiers générés" au lieu de mon dossier "télécharger", vous devez le faire chaque fois que le serveur démarre, ces dossiers sont générés chaque fois que le serveur démarre, par exemple, un fichier change dans votre implémentation.
Une autre option consiste à utiliser une voie côté serveur pour générer le contenu et l'envoyer au navigateur de l'utilisateur pour téléchargement. Par exemple, le suivant recherchera un utilisateur par ID et le renverra comme JSON. L'utilisateur final est invité à enregistrer la réponse dans un fichier avec le nom spécifié dans l'en-tête Content-Disposition. D'autres en-têtes, tels que Expires, pourraient également être ajoutés à la réponse. Si l'utilisateur n'existe pas, un 404 est renvoyé.
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)); } });
Cette méthode a toutefois un gros inconvénient. Les routes côté serveur ne fournissent pas un moyen simple d'accéder à l'utilisateur actuellement connecté. Voir ce problème sur GitHub .