今回は、Koa2 の実装 ファイルのアップロード ダウンロード の事例分析をお届けします。 以下は、実際的なケースです。
はじめに画像やその他のファイルであっても、Web アプリケーションではアップロードとダウンロードが比較的一般的です。 Koa には、機能を迅速に実装するのに役立つ多くの
ミドルウェアファイルアップロードフロントエンドでファイルをアップロードする場合、フォームを通じてアップロードしますが、アップロードされたファイルは通常のパラメーターのようにctx.request.bodyを通じてサーバー側で取得することはできません。 koa-body ミドルウェアを使用して
ファイルのアップロードを処理し、リクエスト本文を ctx.request に入れることができます。 // app.js
const koa = require('koa');
const app = new koa();
const koaBody = require('koa-body');
app.use(koaBody({
multipart: true,
formidable: {
maxFileSize: 200*1024*1024 // 设置上传文件大小最大限制,默认2M
}
}));
app.listen(3001, ()=>{
console.log('koa is listening in 3001');
})
ファイルを受信したら、ファイルをディレクトリに保存し、フロントエンドに URL を返す必要があります。ノード内の処理は
const router = require('koa-router')(); const fs = require('fs'); router.post('/upload', async (ctx){ const file = ctx.request.body.files.file; // 获取上传文件 const reader = fs.createReadStream(file.path); // 创建可读流 const ext = file.name.split('.').pop(); // 获取上传文件扩展名 const upStream = fs.createWriteStream(`upload/${Math.random().toString()}.${ext}`); // 创建可写流 reader.pipe(upStream); // 可读流通过管道写入可写流 return ctx.body = '上传成功'; })
ファイルダウンロードkoa-sendは、ファイルダウンロード機能を実装するために使用できる静的ファイルサービスミドルウェアです。
const router = require('koa-router')(); const send = require('koa-send'); router.post('/download/:name', async (ctx){ const name = ctx.params.name; const path = `upload/${name}`; ctx.attachment(path); await send(ctx, path); })
フロントエンドでダウンロードするには、
window.open とフォーム送信の 2 つの方法があります。ここではより単純な window.open が使用されます。 <button onclick="handleClick()">立即下载</button>
<script>
const handleClick = () => {
window.open('/download/1.png');
}
</script>
<button onclick="handleClick()">立即下载</button> <iframe name="myIframe" style="display:none"></iframe> <script> const handleClick = () => { window.open('/download/1.png', 'myIframe'); } </script>
バッチダウンロードと単一ダウンロードの間に違いはなく、さらに数回ダウンロードを実行するだけです。これには本当に何の問題もありません。非常に多くのファイルを 1 つの圧縮パッケージにまとめて、この圧縮パッケージのみをダウンロードすれば、エクスペリエンスは向上すると思いませんか?
File Packagingarchiverは、Node.jsでクロスプラットフォームパッケージング機能を実現できるモジュールで、zip形式とtar形式をサポートしています。
const router = require('koa-router')(); const send = require('koa-send'); const archiver = require('archiver'); router.post('/downloadAll', async (ctx){ // 将要打包的文件列表 const list = [{name: '1.txt'},{name: '2.txt'}]; const zipName = '1.zip'; const zipStream = fs.createWriteStream(zipName); const zip = archiver('zip'); zip.pipe(zipStream); for (let i = 0; i < list.length; i++) { // 添加单个文件到压缩包 zip.append(fs.createReadStream(list[i].name), { name: list[i].name }) } await zip.finalize(); ctx.attachment(zipName); await send(ctx, zipName); })
フォルダー全体を直接パックする場合、各ファイルを走査して圧縮パッケージに追加する必要はありません
const zipStream = fs.createWriteStream('1.zip'); const zip = archiver('zip'); zip.pipe(zipStream); // 添加整个文件夹到压缩包 zip.directory('upload/'); zip.finalize();
注: フォルダー全体をパッケージする場合、生成された圧縮パッケージ ファイルをこのフォルダーに保存することはできません。そうでない場合は、パックが続行されます。
中国語エンコードの問題ファイル名に中国語が含まれている場合、予期しない状況が発生する可能性があります。そこで、アップロード時に漢字が含まれている場合は、encodeURI()でファイル名をエンコードして保存し、ダウンロード時にdecodeURI()で復号化します。
ctx.attachment(decodeURI(path)); await send(ctx, path);
ctx.attachment Content-Disposition を「attachment」に設定して、クライアントにダウンロードを促すよう指示します。デコードされたファイル名をダウンロードするファイルの名前として使用します。これにより、ローカルにダウンロードした場合でも中国語の名前が表示されます。
ただし、koa-sendのソースコードでは、decodeURIComponent(): でファイルパスをデコードします:
// koa-send path = decode(path) function decode (path) { try { return decodeURIComponent(path) } catch (err) { return -1 } }
このとき、デコード後、中国語を含むパスをダウンロードし、サーバーにエンコードされたパスが保存されるので、当然該当するファイルが見つかりません。
この問題を解決するには、デコードさせないでください。 koa-send ソース コードに触れたくない場合は、代わりに別のミドルウェア koa-sendfile を使用できます。
const router = require('koa-router')(); const sendfile = require('koa-sendfile'); router.post('/download/:name', async (ctx){ const name = ctx.params.name; const path = `upload/${name}`; ctx.attachment(decodeURI(path)); await sendfile(ctx, path); })
この記事の事例を読んだ後は、この方法を習得したと思います。さらに興味深い情報については、php 中国語 Web サイトの他の関連記事に注目してください。
推奨読書:
vue+axiosによるリクエストインターセプト機能の実装方法
以上がファイルのアップロードおよびダウンロードのケース分析の Koa2 実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。