如何在客户端使用 "file-type" NPM 模块?



我正试图使用;文件类型";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模块bundler。一些依赖项通常存在于Node.js环境中,但在浏览器环境中,您可能需要将(polyfill)传递给您的模块bundler。尽管在某些情况下,配置它可能有点棘手,请注意,这是一个由模块bundler处理的非常常见的任务。

我很难理解下一步该怎么做。

该帖子底部的另一条评论表明作者在以下方面取得了成功:

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模块客户端导入JS库?,如何在客户端使用node.js模块系统,如何在客户端机器中使用客户端JavaScript和node.js应用程序调用服务器端NodeJS函数,但我尝试过的任何建议似乎都没有帮助。

终于成功了。如果其他人对此感到困惑,这里有一个解释(很抱歉不够简洁——可能这应该是一篇博客文章…)

为了进一步充实用例,我使用Uppy允许用户将文件上传到AWS S3存储桶。它的工作方式是,当用户上传文件时,Uppy会调用我的服务器,在那里生成一个AWS预签名的URL并将其传递回客户端。然后,客户端使用该预先签名的URL将文件直接上传到S3存储桶,绕过服务器,这样文件就不会在任何时候通过服务器。

我试图解决的问题是,缺少扩展名的文件最终上传的内容/MIME类型设置为";应用程序/八位字节";,因为浏览器、Uppy和S3似乎都依赖于文件扩展名来决定文件类型(而不是解析文件的所谓"魔术字节"),如果文件扩展名丢失,AWS默认为";应用程序/八位字节";。当用户试图打开文件时,这会导致问题,因为它们没有得到正确处理(即,没有扩展名且具有"application/octet"内容/MIME类型的png文件打开下载对话框,而不是预览等)。我还想在扩展名存在的情况下验证MIME类型/文件类型,以便排除某些类型的文件,因此,如果使用了不正确的文件扩展名,文件在以后下载时(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-gbrowserfy";,我在命令行中使用它来创建我在客户端代码中链接到的文件("main.js"):

browserify index.js -o main.js

相关内容

最新更新