私がやりたいこと:内部にファイルが入力されたhtmlフォームを作成します。ファイルが選択されると、ファイル入力はファイルをアップロードし、ファイルIDを取得する必要があります。したがって、フォームが送信されると、ファイルIDがフォームとともに投稿され、データベースに書き込まれます。
短いバージョン:メタデータ(idなど)をファイルに保存したい
シンプルに聞こえますが、LoopBackでそれを行うのに苦労しています。
このトピックについていくつかの会話( 1 、 2 )がありましたが、どちらも解決につながるようには見えなかったので、私はこれを一度見つけるのに良い場所だと思いました。
最も単純な解決策はモデルの関係を使用することですが、LoopBackはファイルストレージサービスとの関係をサポートしていません。バンプ。したがって、たとえばFile
という名前の永続モデルを使用し、デフォルトのcreate、deleteをオーバーライドして、Storage
という名前のファイルストアモデルを保存および削除する必要があります。
これまでの私のセットアップ:
name
、size
、url
およびobjectId
create
をFile.create()
に挿入できるように、リモートフックをbefore url
にセットアップしています私はそこにいます、そして このLoopBackページ によると、私は内部にファイルを持つべきctxを持っています:
File.beforeRemote('create', function(ctx, affectedModelInstance, next) {})`
ctx
とは
ctx.req
:Express Requestオブジェクト。ctx.result
:Express Responseオブジェクト。
さて、今私はExpressページにいますが、かなり迷っており、「ボディ解析ミドルウェア」について何か言っていますが、それが何であるかはわかりません。
私は解決策に近づいているように感じます、助けをいただければ幸いです。このアプローチは正しいですか?
ループバックのファイルにメタデータを保存するためのfullソリューションを次に示します。
コンテナモデルが必要です
common/models/container.json
{
"name": "container",
"base": "Model",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
server/datasources.json
にコンテナのデータソースを作成します。例えば:
...
"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/files.json
{
"name": "files",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string"
},
"type": {
"type": "string"
},
"url": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
そして、files
をcontainer
に接続します:
common/models/files.js
var CONTAINERS_URL = '/api/containers/';
module.exports = function(Files) {
Files.upload = function (ctx,options,cb) {
if(!options) options = {};
ctx.req.params.container = 'common';
Files.app.models.container.upload(ctx.req,ctx.result,options,function (err,fileObj) {
if(err) {
cb(err);
} else {
var fileInfo = fileObj.files.file[0];
Files.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);
}
});
}
});
};
Files.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'}
}
);
};
model-config.json
ファイルにfiles
モデルに追加するAPIファイルを公開するには、正しいデータソースを選択してください。
...
"files": {
"dataSource": "db",
"public": true
}
...
完了!file
フォームフィールドのファイルバイナリデータを使用して、POST /api/files/upload
]を呼び出すことができます。名前、タイプ、URLを返します。
同じ問題がありました。メタデータとアップロード方法を保存する独自のモデルを作成することで解決しました。
Name、type、url、userIdなどの情報を保存するモデルFile
(あなたと同じ)を作成しました
フックでは実行できないため、独自のアップロードリモートメソッドを作成しました。コンテナモデルは、 loopback-component-storage で作成されるモデルです。
var fileInfo = fileObj.files.myFile[0];
ここで、myFileはファイルアップロードのフィールド名であるため、それに応じて変更する必要があります。フィールドを指定しない場合、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を使用できます。
ディレクトリでbootサンプルコードを使用:
module.exports = function(server) {
server.dataSources.filestorage.connector.allowedContentTypes = ["image/jpg", "image/jpeg", "image/png"];
}
私はそれが誰かを助けることを願っています。
シナリオによっては、署名などを利用して、Amazon S3、TransloadIT(画像処理用)、または同様のサービスに直接アップロードできるようにすることを検討する価値があります。
このコンセプトに関する最初の決定は、GraphQLを使用しているため、GraphQLを介したマルチパートフォームのアップロードを回避したいということでした。さらに、リソースを(大規模な)アップロードおよび関連するファイルの検証と処理で拘束することなく、これらのサーバーの効率を維持したかったのです。
ワークフローは次のようになります。
バナーやアバターのアップロードなどを行う場合、ステップ1はすでに存在するため、そのステップはスキップします。
さらに、S3バケットにSNSまたはSQS通知を追加して、関連するオブジェクトにファイルが添付されたことをデータベースで確認できます-効果的にステップ4。
これは複数のステップからなるプロセスですが、コアAPI内でファイルのアップロードを処理する必要性を排除してうまく機能します。これまでのところ、これはユーザーアバターやレコードへのPDFの添付などの初期実装(このプロジェクトの初期)からうまく機能しています。
参照例:
http://docs.aws.Amazon.com/AmazonS3/latest/dev/UsingHTTPPOST.html
loopback 3 and Postmanでその問題を抱えている他の人のために、POSTで接続がハングする(またはERR_EMPTY_RESPONSEを返す)(ここのコメントで見られる)...このシナリオの問題は、Postmanが使用することですContent-Type "application/x-www-form-urlencoded"として!
そのヘッダーを削除して、「Accept」=「multipart/form-data」を追加してください。この動作のループバックでバグをすでに提出しています
AngularJS SDKユーザーの場合... Container.upload()などの生成されたメソッドを使用する場合は、lb-services.js
を使用して、Content-Typeヘッダーをundefined
に設定します。これにより、クライアントはContent-Typeヘッダーを設定し、境界値を自動的に追加できます。次のようになります。
"upload": {
url: urlBase + "/containers/:container/upload",
method: "POST",
headers: {"Content-Type": undefined}
}
データを"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();
})