【问题标题】:How to Use "file-type" NPM Module Client-Side?如何在客户端使用“文件类型”NPM 模块?
【发布时间】:2021-06-24 09:16:07
【问题描述】:

我正在尝试使用"file-type" NPM module(我在服务器上工作)客户端在将文件上传到 S3 存储桶之前验证 mime 类型。

模块的readme 包含一个在浏览器中使用它的示例:

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 的回答 from this question:

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。这没有帮助(错误没有改变)。

我找到了similar question in the module's Github repository,这表明:

虽然这个模块主要是为 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 模块(在我的脑海中仍然很模糊)并尝试了上述代码的各种变体 - 非常感谢一些指导(第一次在这里发布问题 -请对我放轻松!)。

谢谢!

编辑:我不认为这是重复的 - 我确实审查了 How to import JS library from node_modules、Meteor Npm-module client-side?、how to use node.js module system on the clientside、How to call a server-side NodeJS function using client-side JavaScript 和 Node Js application in client machine,但我没有尝试任何建议似乎有帮助。

【问题讨论】:

    标签: javascript node.js mime-types file-type


    【解决方案1】:

    终于搞定了。万一其他人对此感到困惑,这里有一个解释(为缺乏简洁而道歉 - 可能这应该是一篇博文......)。

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

    我试图解决的问题是缺少扩展名的文件最终上传时内容/MIME 类型设置为“application/octet”,因为浏览器、Uppy 和 S3 似乎都依赖文件扩展名来决定文件类型(而不是解析文件的所谓“魔术字节”),如果缺少文件扩展名,AWS 默认为“应用程序/八位字节”。当用户尝试打开文件时,这会导致问题,因为它们没有得到正确处理(即没有扩展名且具有“应用程序/八位字节”内容/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 -g browserify”在命令行安装了 Browserify,我在命令行使用它来创建文件(“main.js”)。 js") 我在客户端代码中链接到:

    browserify index.js -o main.js
    

    【讨论】:

      猜你喜欢
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-24
      • 1970-01-01
      • 2021-01-05
      • 2016-05-06
      • 1970-01-01
      相关资源
      最近更新 更多