我正在尝试使用“文件类型”NPM 模块(我在服务器上工作)客户端在文件上传到 S3 存储桶之前验证 MIME 类型。
该模块的自述文件包括在浏览器中使用它的示例:
const FileType = require('file-type/browser');
const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg';
(async () => {
const response = await fetch(url);
const fileType = await FileType.fromStream(response.body);
console.log(fileType);
//=> {ext: 'jpg', mime: 'image/jpeg'}
})();
由于“需要”,这显然不能直接在浏览器中工作,如果我直接链接到 NPM 文件,我会得到:
Uncaught ReferenceError: require is not defined
所以我尝试使用 Webpack(我根本不精通它,但遵循官方 Webpack 教程和其他一些教程)创建一个“main.js”文件,然后通过脚本标签访问它.
例如,通过 Webpack 运行它:
import * as mimeFromBuffer from 'file-type/browser.js';
export function mimeTyping(mimeValidationBytes){
(async () => {
const fileType = await mimeFromBuffer(mimeValidationBytes);
console.log(fileType);
//=> {ext: 'jpg', mime: 'image/jpeg'}
})();
return;
}
当我调用mimeTyping
客户端时,结果如下:
Uncaught ReferenceError: mimeTyping is not defined
我在浏览器中从这个问题中尝试了 Vinay 的回答:
import fileType from 'file-type';
const blob = file.slice(0, fileType.minimumBytes);
const reader = new FileReader();
reader.onloadend = function(e) {
if (e.target.readyState !== FileReader.DONE) {
return;
}
const bytes = new Uint8Array(e.target.result);
const { ext, mime } = fileType.fromBuffer(bytes);
// ext is the desired extension and mime is the mimetype
};
reader.readAsArrayBuffer(blob);
这让我明白:
Uncaught SyntaxError: Cannot use import statement outside a module
我对这个错误进行了一些研究,一个常见的解决方案是添加"type":"module"
到package.json
. 这没有帮助(错误没有改变)。
我在模块的 Github 存储库中发现了一个类似的问题,它表明:
虽然这个模块主要是为 Node.js 设计的,但也可以在浏览器中使用它。这确实是“文件类型/浏览器”的目的所在。它为 JavaScript 模块捆绑器提供了正确的依赖项和正确的功能。一些依赖项,通常存在于 Node.js 环境中,但在浏览器环境中缺失,您可能需要将 (polyfill) 传递给您的模块打包器。尽管在某些情况下配置它可能有点棘手,但请注意,这是由模块捆绑器处理的一项非常常见的任务。
我正在努力理解接下来的步骤是什么。
该线程底部的另一条评论表明作者在以下方面取得了成功:
import { fromBuffer } from 'file-type/core';
...
const buffer = await uploadedFile.arrayBuffer();
const types = await fromBuffer(buffer);
我不确定如何实现它,以及我需要什么其他代码(我猜这会传递给 Webpack,并且可能需要一个export
语句,然后是import
客户端?)
我试过将其传递给 Webpack:
const fileType = require('file-type/browser');
module.exports = fileType;
但是再次链接到输出文件会得到:
Uncaught SyntaxError: Cannot use import statement outside a module
我想我从概念上理解我需要做什么:将 NPM 模块传递给 Webpack,Webpack 反过来解析它并找到任何依赖项,获取这些依赖项,并创建一个我可以在客户端使用的 JavaScript 文件。看来我在那里做错了什么。
我花了几天时间试图了解如何使用 NPM 模块客户端(在我的脑海中仍然很模糊)并尝试了上述代码的各种变体 - 非常感谢一些指导(第一次在这里发布问题 - 请放轻松在我身上!)。
谢谢!
编辑:我不认为这是重复的 - 我确实回顾了如何从 node_modules、Meteor Npm -module client-side导入 JS 库?,如何在客户端使用 node.js 模块系统,如何在客户端机器上使用客户端 JavaScript和Node Js 应用程序调用服务器端 NodeJS 函数,但我尝试过的任何建议似乎都没有帮助。
终于得到了这个工作。万一其他人被困在这个问题上,这里有一个解释(为缺乏简洁而道歉 - 可能这应该是一篇博客文章......)。
为了进一步充实用例,我使用Uppy来允许用户将文件上传到 AWS S3 存储桶。它的工作方式是,当用户上传文件时,Uppy 会调用我的服务器,在那里生成 AWS 预签名 URL 并将其传递回客户端。然后,客户端使用该预签名 URL 将文件直接上传到 S3 存储桶,绕过服务器,这样文件在任何时候都不会通过服务器。
我试图解决的问题是缺少扩展名的文件最终上传的内容/MIME 类型设置为“应用程序/八位字节”,因为浏览器、Uppy 和 S3 似乎都依赖文件扩展名来决定文件类型(而不是解析文件的所谓“魔术字节”),如果缺少文件扩展名,AWS 默认为“application/octet”。当用户尝试打开文件时,这会导致问题,因为它们没有得到正确处理(即没有扩展名且具有“应用程序/八位字节”内容/MIME 类型的 png 文件打开下载对话框而不是被预览等)。我还想在扩展名存在的情况下验证 MIME 类型/文件类型,以便我可以排除某些类型的文件,
我使用“文件类型”NPM 模块来确定 mimetype 服务器端,这很简单,但是在生成 AWS 预签名 URL 时更改文件的内容类型/MIME 类型不足以解决问题 - 它仍然被上传为“应用程序/八位字节”。我想使用相同的模块客户端,因此我们在客户端上获得与在服务器上完全相同的结果,并且在任何情况下都需要确定 MIME 类型并相应地设置它在上传前但预签名后的 URL。我不知道如何做到这一点(即使用“文件类型”客户端 - 我的问题的核心)。
我终于放弃了 Webpack - 我尝试过的一切都不奏效。所以我切换到 Browserify,“文件类型”存储库中的示例浏览器代码立即生效!因此,我不得不试图弄清楚如何通过 Browserify 传递一个函数以在客户端代码中使用。
这对我来说是不可能的 - 我不知道如何将异步 IIFE 传递给我的代码。因此,我将我的 Uppy 代码移动到我传递给 Browserify 的代码中:
// Get the dependency, which we've added to node via "npm install file-type":
const FileType = require('file-type/browser');
// When the user adds a file for upload to Uppy...
uppy.on('file-added', (file) => {
// 1. Create a filereader:
const filereader = new FileReader();
filereader.onloadend = function(evt) {
// 4. Once the filereader has successfully finished reading the file...
if (evt.target.readyState === FileReader.DONE) {
// Get the unsigned 8 bit int8Array (ie Uint8Array) of the 600 bytes (this looks like '[119,80,78,71...]'):
const uint = new Uint8Array(evt.target.result);
// Determine the mime type using the "file-type" NPM package:
(async () => {
// Pass in our 600 bytes ("uint"):
const fileType = await FileType.fromBuffer(uint);
console.log(fileType); // outputs => {ext: 'jpg', mime: 'image/jpeg'}
// Do some validation here...
//
// Assign the results to the file for upload - we're done!:
file.extension = fileType.ext;
file.meta.type = fileType.mime;
file.type = fileType.mime;
})();
}
}
// 2. Grab the first 600 bytes of the file for mime type analysis server side - most mime
// types use the first few bytes, but some (looking at you, Microsoft...) start at the
// 513th byte; ISO CD files start at the 32,770th byte, so we'll ignore those rather than
// send that much data for each file - users of this system certainly aren't expected to
// upload ISO CD files! Also, some .zip files may start their identifying bytes at the
// 29,153nd byte - we ignore those too (mostly, .zip files start at the first, 31st, or 527th byte).
const blob = file.data.slice(0, 600);
// 3. Start reading those 600 bytes...continues above at 'filereader.onloadend':
filereader.readAsArrayBuffer(blob);
})
这一切都进入了一个我称之为“index.js”的文件,然后,通过“npm install -g browserify”在命令行安装了 Browserify,我在命令行中使用它来创建文件(“main.js”)我在客户端代码中链接到:
browserify index.js -o main.js
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句