如何在LoopBack中存储具有元数据的文件?

我想做什么:有一个HTML表单,里面有一个文件input。 当select一个文件时,文件input应该上传文件,并获得一个文件ID,所以当表单被提交时,文件ID被张贴在表单上并写入数据库。

较短的版本: 我想用我的文件存储元数据(例如id)。

听起来很简单,但我很难在LoopBack中做到这一点。

关于这个话题已经有了一些对话( 1,2 ),似乎也没有find解决办法,所以我认为这可能是一个永远find一个好地方的好地方。

最简单的解决scheme是使用模型关系,但是LoopBack不支持与文件存储服务的关系。 磕碰。 因此,我们必须使用一个名为File的持久化模型,并覆盖默认的create,delete,以便从文件存储模型中保存和删除 – 名为Storage

我的设置到目前为止:

  • 我有一个模型/ API /存储连接到环回存储服务,并成功地将文件保存到本地文件系统。
  • 我有一个PersistedModel连接到Mongo与文件元数据: namesizeurlobjectId
  • create之前设置了一个远程钩子,因此可以先保存文件,然后将url注入到File.create()

我在那里,根据这个LoopBack页面 ,我有应该在里面的文件的ctx:

 File.beforeRemote('create', function(ctx, affectedModelInstance, next) {})` 

什么是ctx

ctx.req :快速请求对象。
ctx.result :快速响应对象。

好的,所以现在我在Express页面,很迷茫,这是一个关于“身体parsing中间件”的东西,我不知道它可能是什么。

我觉得我接近解决scheme, 任何帮助将不胜感激 。 这种方法是对的吗?

以下是以回送方式存储元数据和文件的完整解决scheme。

你需要一个容器模型

common/models/container.json

 { "name": "container", "base": "Model", "idInjection": true, "options": { "validateUpsert": true }, "properties": {}, "validations": [], "relations": {}, "acls": [], "methods": [] } 

server/datasources.json为您的容器创build数据源。 例如:

 ... "storage": { "name": "storage", "connector": "loopback-component-storage", "provider": "filesystem", "root": "/var/www/storage", "maxFileSize": "52428800" } ... 

您将需要在server/model-config.json中将此模型的数据源设置为您具有的loopback-component-storage

 ... "container": { "dataSource": "storage", "public": true } ... 

您还需要一个文件模型来存储元数据并处理容器调用:

common/models/file.json

 { "name": "file", "base": "PersistedModel", "idInjection": true, "options": { "validateUpsert": true }, "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "url": { "type": "string", "required": true } }, "validations": [], "relations": {}, "acls": [], "methods": [] } 

现在连接filecontainer

common/models/file.js

 var CONTAINERS_URL = '/api/containers/'; module.exports = function(File) { File.upload = function (ctx,options,cb) { if(!options) options = {}; ctx.req.params.container = 'common'; File.app.models.container.upload(ctx.req,ctx.result,options,function (err,fileObj) { if(err) { cb(err); } else { var fileInfo = fileObj.files.file[0]; File.create({ name: fileInfo.name, type: fileInfo.type, container: fileInfo.container, url: CONTAINERS_URL+fileInfo.container+'/download/'+fileInfo.name },function (err,obj) { if (err !== null) { cb(err); } else { cb(null, obj); } }); } }); }; File.remoteMethod( 'upload', { description: 'Uploads a file', accepts: [ { arg: 'ctx', type: 'object', http: { source:'context' } }, { arg: 'options', type: 'object', http:{ source: 'query'} } ], returns: { arg: 'fileObject', type: 'object', root: true }, http: {verb: 'post'} } ); }; 

完成! 您现在可以在file表单字段中使用文件二进制数据调用POST /api/file/upload 。 您将返回id,名称,types和url。

我有同样的问题。 我通过创build自己的模型来存储元数据和我自己的上传方法来解决这个问题。

  1. 我创build了一个模型File ,它将存储像名称,types,url,userId(与你的相同)

  2. 我创build了我自己的上传远程方法,因为我无法做到这一点的钩子。 容器模型是由回送组件存储创build的模型。

  3. var fileInfo = fileObj.files.myFile[0]; 这里myFile是file upload的字段名,所以你必须相应地改变它。 如果你没有指定任何字段,那么它将作为fileObj.file.null[0]这段代码没有正确的错误检查,在生产环境中部署之前就做好了

      File.uploadFile = function (ctx,options,cb) { File.app.models.container.upload(ctx.req,ctx.result,options,function (err,fileObj) { if(err) cb(err); else{ // Here myFile is the field name associated with upload. You should change it to something else if you var fileInfo = fileObj.files.myFile[0]; File.create({ name: fileInfo.name, type: fileInfo.type, container: fileInfo.container, userId: ctx.req.accessToken.userId, url: CONTAINERS_URL+fileInfo.container+'/download/'+fileInfo.name // This is a hack for creating links },function (err,obj) { if(err){ console.log('Error in uploading' + err); cb(err); } else{ cb(null,obj); } }); } }); }; File.remoteMethod( 'uploadFile', { description: 'Uploads a file', accepts: [ { arg: 'ctx', type: 'object', http: { source:'context' } }, { arg: 'options', type 'object', http:{ source: 'query'} } ], returns: { arg: 'fileObject', type: 'object', root: true }, http: {verb: 'post'} } ); 

对于那些正在寻找“如何在上传文件之前检查文件格式”这个问题的答案的人。

在这种情况下,我们可以使用可选参数allowedContentTypes

在目录引导中使用示例代码:

 module.exports = function(server) { server.dataSources.filestorage.connector.allowedContentTypes = ["image/jpg", "image/jpeg", "image/png"]; } 

我希望这会帮助别人。

只需将数据作为"params"对象传递,并在服务器上,您可以将其作为ctx.req.query

例如

在客户端

 Upload.upload( { url: '/api/containers/container_name/upload', file: file, //Additional data with file params:{ orderId: 1, customerId: 1, otherImageInfo:[] } }); 

在服务器端

假设您的存储模型名称是container

 Container.beforeRemote('upload', function(ctx, modelInstance, next) { //OUPTUTS: {orderId:1, customerId:1, otherImageInfo:[]} console.log(ctx.req.query); next(); }) 

根据您的情况,可能需要查看使用签名或类似的function,以允许直接上传到Amazon S3,TransloadIT(用于image processing)或类似的服务。

我们对这个概念的第一个决定是,在我们使用GraphQL的时候,我们希望避免通过GraphQL来进行多部分的表单上传,而这反过来又需要转移到它后面的Loopback服务上。 另外,我们希望保持这些服务器的高效率,而不用占用(大量)上传和关联文件validation和处理的资源。

您的工作stream程可能如下所示:

  1. 创build数据库logging
  2. 返回loggingID和file upload签名数据(包括S3存储桶或TransloadIT端点,以及任何authentication令牌)
  3. 客户端上传到端点

对于像横幅或头像上传的情况,步骤1已经存在,所以我们跳过这一步。

另外,您还可以将SNS或SQS通知添加到您的S3存储桶中,以便在数据库中确认相关对象现在已经附加了一个文件 – 实际上是第4步。

这是一个多步骤的过程,但可以很好地解决在核心API中处理file upload的需要。 到目前为止,从我们最初的实施(在这个项目的早期阶段),这个工作就像用户头像以及将PDF附加到logging一样。

参考示例:

http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingHTTPPOST.html

https://transloadit.com/docs/#authentication

对于任何其他问题的回环3和Postman ,在POST,连接挂起(或返回ERR_EMPTY_RESPONSE)(在这里看到一些注释)…在这种情况下的问题是,该邮递员使用内容types“应用程序/ X WWW的forms,进行了urlencoded“!

请删除该标题并添加“Accept”=“multipart / form-data”。 我已经在这个行为的回送中提交了一个bug

对于AngularJS SDK用户…如果您想要使用像Container.upload()这样的生成方法,您可能需要添加一行来configurationlb-services.js的方法,将Content-Type头设置为undefined 。 这将允许客户端设置Content-Type标题并自动添加边界值。 会看起来像这样:

  "upload": { url: urlBase + "/containers/:container/upload", method: "POST", headers: {"Content-Type": undefined} }