npm formidable package logo

# formidable [![npm version][npmv-img]][npmv-url] [![MIT license][license-img]][license-url] [![Libera Manifesto][libera-manifesto-img]][libera-manifesto-url] [![Twitter][twitter-img]][twitter-url] > A Node.js module for parsing form data, especially file uploads. [![Code style][codestyle-img]][codestyle-url] [![codecoverage][codecov-img]][codecov-url] [![linux build status][linux-build-img]][build-url] [![windows build status][windows-build-img]][build-url] [![macos build status][macos-build-img]][build-url] Se você tiver qualquer tipo de pergunta sobre _como_ fazer, por favor leia o [Contributing Guia][contributing-url] e [Código de Conduta][code_of_conduct-url] documentos.
Para relatórios de bugs e solicitações de recursos, [crie uma issue][open-issue-url] ou ping [@tunnckoCore / @3a1FcBx0](https://twitter.com/3a1FcBx0) no Twitter. [![Conventional Commits][ccommits-img]][ccommits-url] [![Minimum Required Nodejs][nodejs-img]][npmv-url] [![Tidelift Subscription][tidelift-img]][tidelift-url] [![Buy me a Kofi][kofi-img]][kofi-url] [![Renovate App Status][renovateapp-img]][renovateapp-url] [![Make A Pull Request][prs-welcome-img]][prs-welcome-url] Este projeto é [semanticamente versionado](https://semver.org) e está disponível como parte da [Assinatura Tidelift][tidelift-url] para nível profissional garantias, suporte aprimorado e segurança. [Saiba mais.](https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise) _Os mantenedores do `formidable` e milhares de outros pacotes estão trabalhando com Tidelift para fornecer suporte comercial e manutenção para o Open Source dependências que você usa para construir seus aplicativos. Economize tempo, reduza riscos e melhorar a integridade do código, enquanto paga aos mantenedores das dependências exatas que você usar._ [![][npm-weekly-img]][npmv-url] [![][npm-monthly-img]][npmv-url] [![][npm-yearly-img]][npmv-url] [![][npm-alltime-img]][npmv-url] ## Status do Projeto: Mantido _Verifique [VERSION NOTES](https://github.com/node-formidable/formidable/blob/master/VERSION_NOTES.md) para obter mais informações sobre os planos v1, v2 e v3, NPM dist-tags e branches._ Este módulo foi inicialmente desenvolvido por [**@felixge**](https://github.com/felixge) para [Transloadit](http://transloadit.com/), um serviço focado em upload e codificação de imagens e vídeos. Foi testado em batalha contra centenas de GBs de uploads de arquivos de uma grande variedade de clientes e é considerado pronto para produção e é usado na produção por anos. Atualmente, somos poucos mantenedores tentando lidar com isso. :) Mais contribuidores são sempre bem-vindos! ❤️ Pule [issue #412](https://github.com/felixge/node-formidable/issues/412) que está fechado, mas se você estiver interessado, podemos discuti-lo e adicioná-lo após regras estritas, como ativar o Two-Factor Auth em suas contas npm e GitHub. ## Destaques - [Rápido (~ 900-2500 mb/seg)](#benchmarks) e analisador multiparte de streaming - Gravar uploads de arquivos automaticamente no disco (opcional, consulte [`options.fileWriteStreamHandler`](#options)) - [API de plug-ins](#useplugin-plugin) - permitindo analisadores e plug-ins personalizados - Baixo consumo de memória - Tratamento de erros gracioso - Cobertura de teste muito alta ## Instalar Este projeto requer `Node.js >= 10.13`. Instale-o usando [yarn](https://yarnpkg.com) ou [npm](https://npmjs.com).
_Nós altamente recomendamos usar o Yarn quando pensar em contribuir para este projeto._ Este é um pacote de baixo nível e, se você estiver usando uma estrutura de alto nível, _pode_ já estar incluído. Verifique os exemplos abaixo e a pasta [examples/](https://github.com/node-formidable/formidable/tree/master/examples). ``` # v2 npm install formidable npm install formidable@v2 # v3 npm install formidable@v3 ``` _**Nota:** Em um futuro próximo, a v3 será publicada na dist-tag `latest` do NPM. Versões futuras não prontas serão publicadas nas dist-tags `*-next` para a versão correspondente._ ## Exemplos Para mais exemplos veja o diretório `examples/`. ### com módulo http Node.js Analisar um upload de arquivo de entrada, com o [Módulo `http` integrado do Node.js](https://nodejs.org/api/http.html). ```js import http from 'node:http'; import formidable, {errors as formidableErrors} from 'formidable'; const server = http.createServer((req, res) => { if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') { // analisar um upload de arquivo const form = formidable({}); form.parse(req, (err, fields, files) => { if (err) { // exemplo para verificar um erro muito específico if (err.code === formidableErrors.maxFieldsExceeded) { } res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' }); res.end(String(err)); return; } res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ fields, files }, null, 2)); }); return; } // mostrar um formulário de upload de arquivo res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(`

With Node.js "http" module

Text field title:
File:
`); }); server.listen(8080, () => { console.log('Server listening on http://localhost:8080/ ...'); }); ``` ### com Express.js Existem várias variantes para fazer isso, mas o Formidable só precisa do Node.js Request stream, então algo como o exemplo a seguir deve funcionar bem, sem nenhum middleware [Express.js](https://ghub.now.sh/express) de terceiros. Ou tente o [examples/with-express.js](https://github.com/node-formidable/formidable/blob/master/examples/with-express.js) ```js import express from 'express'; import formidable from 'formidable'; const app = express(); app.get('/', (req, res) => { res.send(`

With "express" npm package

Text field title:
File:
`); }); app.post('/api/upload', (req, res, next) => { const form = formidable({}); form.parse(req, (err, fields, files) => { if (err) { next(err); return; } res.json({ fields, files }); }); }); app.listen(3000, () => { console.log('Server listening on http://localhost:3000 ...'); }); ``` ### com Koa e Formidable Claro, com [Koa v1, v2 ou future v3](https://ghub.now.sh/koa) as coisas sao muito parecidas. Você pode usar `formidable` manualmente como mostrado abaixo ou através do pacote [koa-better-body](https://ghub.now.sh/koa-better-body) que é usando `formidable` sob o capô e suporte a mais recursos e diferentes corpos de solicitação, verifique sua documentação para mais informações. _Nota: este exemplo está assumindo Koa v2. Esteja ciente de que você deve passar `ctx.req` que é a solicitação do Node.js e **NÃO** o `ctx.request` que é a solicitação do Koa objeto - há uma diferença._ ```js import Koa from 'Koa'; import formidable from 'formidable'; const app = new Koa(); app.on('error', (err) => { console.error('server error', err); }); app.use(async (ctx, next) => { if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') { const form = formidable({}); // não muito elegante, mas é por enquanto se você não quiser usar `koa-better-body` // ou outros middlewares. await new Promise((resolve, reject) => { form.parse(ctx.req, (err, fields, files) => { if (err) { reject(err); return; } ctx.set('Content-Type', 'application/json'); ctx.status = 200; ctx.state = { fields, files }; ctx.body = JSON.stringify(ctx.state, null, 2); resolve(); }); }); await next(); return; } // mostrar um formulário de upload de arquivo ctx.set('Content-Type', 'text/html'); ctx.status = 200; ctx.body = `

With "koa" npm package

Text field title:
File:
`; }); app.use((ctx) => { console.log('The next middleware is called'); console.log('Results:', ctx.state); }); app.listen(3000, () => { console.log('Server listening on http://localhost:3000 ...'); }); ``` ## Benchmarks O benchmark é bastante antigo, da antiga base de código. Mas talvez seja bem verdade. Anteriormente, os números giravam em torno de ~ 500 mb/s. Atualmente com a mudança para o novo Node.js Streams API, é mais rápido. Você pode ver claramente as diferenças entre as versões do Node. _Observação: um benchmarking muito melhor pode e deve ser feito no futuro._ Benchmark realizado em 8 GB de RAM, Xeon X3440 (2,53 GHz, 4 núcleos, 8 threads) ``` ~/github/node-formidable master ❯ nve --parallel 8 10 12 13 node benchmark/bench-multipart-parser.js ⬢ Node 8 1261.08 mb/sec ⬢ Node 10 1113.04 mb/sec ⬢ Node 12 2107.00 mb/sec ⬢ Node 13 2566.42 mb/sec ``` ![benchmark 29 de janeiro de 2020](./benchmark/2020-01-29_xeon-x3440.png) ## API ### Formidable / IncomingForm Todos os mostrados são equivalentes. _Por favor, passe [`options`](#options) para a função/construtor, não atribuindo eles para a instância `form`_ ```js import formidable from 'formidable'; const form = formidable(options); ``` ### Opções Veja seus padrões em [src/Formidable.js DEFAULT_OPTIONS](./src/Formidable.js) (a constante `DEFAULT_OPTIONS`). - `options.encoding` **{string}** - padrão `'utf-8'`; define a codificação para campos de formulário de entrada, - `options.uploadDir` **{string}** - padrão `os.tmpdir()`; o diretório para colocar os uploads de arquivos. Você pode movê-los mais tarde usando `fs.rename()`. - `options.keepExtensions` **{boolean}** - padrão `false`; incluir as extensões dos arquivos originais ou não - `options.allowEmptyFiles` **{boolean}** - padrão `false`; permitir upload de arquivos vazios - `options.minFileSize` **{number}** - padrão `1` (1byte); o tamanho mínimo do arquivo carregado. - `options.maxFiles` **{number}** - padrão `Infinity`; limitar a quantidade de arquivos carregados, defina Infinity para ilimitado - `options.maxFileSize` **{number}** - padrão `200 * 1024 * 1024` (200mb); limitar o tamanho de cada arquivo carregado. - `options.maxTotalFileSize` **{number}** - padrão `options.maxFileSize`; limitar o tamanho do lote de arquivos carregados. - `options.maxFields` **{number}** - padrão `1000`; limite o número de campos, defina Infinity para ilimitado - `options.maxFieldsSize` **{number}** - padrão `20 * 1024 * 1024` (20mb); limitar a quantidade de memória que todos os campos juntos (exceto arquivos) podem alocar em bytes. - `options.hashAlgorithm` **{string | false}** - padrão `false`; incluir checksums calculados para arquivos recebidos, defina isso para algum algoritmo de hash, consulte [crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options) para algoritmos disponíveis - `options.fileWriteStreamHandler` **{function}** - padrão `null`, que por padrão grava no sistema de arquivos da máquina host cada arquivo analisado; A função deve retornar uma instância de um [fluxo gravável](https://nodejs.org/api/stream.html#stream_class_stream_writable) que receberá os dados do arquivo carregado. Com esta opção, você pode ter qualquer comportamento personalizado em relação a onde os dados do arquivo carregado serão transmitidos. Se você deseja gravar o arquivo carregado em outros tipos de armazenamento em nuvem (AWS S3, armazenamento de blob do Azure, armazenamento em nuvem do Google) ou armazenamento de arquivo privado, esta é a opção que você está procurando. Quando esta opção é definida, o comportamento padrão de gravar o arquivo no sistema de arquivos da máquina host é perdido. - `options.filename` **{function}** - padrão `undefined` Use-o para controlar newFilename. Deve retornar uma string. Será associado a options.uploadDir. - `options.filter` **{function}** - função padrão que sempre retorna verdadeiro. Use-o para filtrar arquivos antes de serem carregados. Deve retornar um booleano. #### `options.filename` **{function}** function (name, ext, part, form) -> string onde a parte pode ser decomposta como ```js const { originalFilename, mimetype} = part; ``` _**Observação:** Se este tamanho de campos combinados, ou tamanho de algum arquivo for excedido, um O evento `'error'` é disparado._ ```js // A quantidade de bytes recebidos para este formulário até agora. form.bytesReceived; ``` ```js // O número esperado de bytes neste formulário. form.bytesExpected; ``` #### `options.filter` **{function}** function ({name, originalFilename, mimetype}) -> boolean **Observação:** use uma variável externa para cancelar todos os uploads no primeiro erro ```js const options = { filter: function ({name, originalFilename, mimetype}) { // manter apenas imagens return mimetype && mimetype.includes("image"); } }; ``` ### .parse(request, callback) Analisa uma `request` do Node.js recebida contendo dados de formulário. Se `callback` for fornecido, todos os campos e arquivos são coletados e passados para o retorno de chamada. ```js const form = formidable({ uploadDir: __dirname }); form.parse(req, (err, fields, files) => { console.log('fields:', fields); console.log('files:', files); }); ``` Você pode substituir esse método se estiver interessado em acessar diretamente o fluxo de várias partes. Fazer isso desativará qualquer processamento de eventos `'field'` / `'file'` que ocorreria de outra forma, tornando você totalmente responsável por lidar com o processamento. Sobre `uploadDir`, dada a seguinte estrutura de diretório ``` project-name ├── src │ └── server.js │ └── uploads └── image.jpg ``` `__dirname` seria o mesmo diretório que o próprio arquivo de origem (src) ```js `${__dirname}/../uploads` ``` para colocar arquivos em uploads. Omitir `__dirname` tornaria o caminho relativo ao diretório de trabalho atual. Isso seria o mesmo se server.js fosse iniciado a partir de src, mas não de project-name. `null` usará o padrão que é `os.tmpdir()` Nota: Se o diretório não existir, os arquivos carregados são __silenciosamente descartados__. Para ter certeza de que existe: ```js import {createNecessaryDirectoriesSync} from "filesac"; const uploadPath = `${__dirname}/../uploads`; createNecessaryDirectoriesSync(`${uploadPath}/x`); ``` No exemplo abaixo, escutamos alguns eventos e os direcionamos para o ouvinte `data`, para que você possa fazer o que quiser lá, com base em se é antes do arquivo ser emitido, o valor do cabeçalho, o nome do cabeçalho, no campo , em arquivo e etc. Ou a outra maneira poderia ser apenas substituir o `form.onPart` como é mostrado um pouco mais tarde. ```js form.once('error', console.error); form.on('fileBegin', (formname, file) => { form.emit('data', { name: 'fileBegin', formname, value: file }); }); form.on('file', (formname, file) => { form.emit('data', { name: 'file', formname, value: file }); }); form.on('field', (fieldName, fieldValue) => { form.emit('data', { name: 'field', key: fieldName, value: fieldValue }); }); form.once('end', () => { console.log('Done!'); }); // Se você quiser personalizar o que quiser... form.on('data', ({ name, key, value, buffer, start, end, formname, ...more }) => { if (name === 'partBegin') { } if (name === 'partData') { } if (name === 'headerField') { } if (name === 'headerValue') { } if (name === 'headerEnd') { } if (name === 'headersEnd') { } if (name === 'field') { console.log('field name:', key); console.log('field value:', value); } if (name === 'file') { console.log('file:', formname, value); } if (name === 'fileBegin') { console.log('fileBegin:', formname, value); } }); ``` ### .use(plugin: Plugin) Um método que permite estender a biblioteca Formidable. Por padrão, incluímos 4 plug-ins, que são essencialmente adaptadores para conectar os diferentes analisadores integrados. **Os plugins adicionados por este método estão sempre ativados.** _Consulte [src/plugins/](./src/plugins/) para uma visão mais detalhada dos plug-ins padrão._ O parâmetro `plugin` tem essa assinatura: ```typescript function(formidable: Formidable, options: Options): void; ``` A arquitetura é simples. O `plugin` é uma função que é passada com a instância Formidable (o `form` nos exemplos README) e as opções. **Observação:** o contexto `this` da função do plug-in também é a mesma instância. ```js const form = formidable({ keepExtensions: true }); form.use((self, options) => { // self === this === form console.log('woohoo, custom plugin'); // faça suas coisas; verifique `src/plugins` para inspiração }); form.parse(req, (error, fields, files) => { console.log('done!'); }); ``` **Importante observar**, é que dentro do plugin `this.options`, `self.options` e `options` PODEM ou NÃO ser iguais. A melhor prática geral é sempre usar o `this`, para que você possa testar seu plugin mais tarde de forma independente e mais fácil. Se você quiser desabilitar alguns recursos de análise do Formidable, você pode desabilitar o plugin que corresponde ao analisador. Por exemplo, se você deseja desabilitar a análise de várias partes (para que o [src/parsers/Multipart.js](./src/parsers/Multipart.js) que é usado em [src/plugins/multipart.js](./src/plugins/multipart.js)), então você pode removê-lo do `options.enabledPlugins`, assim ```js import formidable, {octetstream, querystring, json} from "formidable"; const form = formidable({ hashAlgorithm: 'sha1', enabledPlugins: [octetstream, querystring, json], }); ``` **Esteja ciente** de que a ordem _PODE_ ser importante também. Os nomes correspondem 1:1 a arquivos na pasta [src/plugins/](./src/plugins). Solicitações pull para novos plug-ins integrados PODEM ser aceitas - por exemplo, analisador de querystring mais avançado. Adicione seu plugin como um novo arquivo na pasta `src/plugins/` (em letras minúsculas) e siga como os outros plugins são feitos. ### form.onPart Se você quiser usar Formidable para manipular apenas algumas partes para você, você pode fazer alguma coisa similar. ou ver [#387](https://github.com/node-formidable/node-formidable/issues/387) para inspiração, você pode, por exemplo, validar o tipo mime. ```js const form = formidable(); form.onPart = (part) => { part.on('data', (buffer) => { // faça o que quiser aqui }); }; ``` Por exemplo, force Formidable a ser usado apenas em "partes" que não sejam de arquivo (ou seja, html Campos) ```js const form = formidable(); form.onPart = function (part) { // deixe formidável lidar apenas com partes não arquivadas if (part.originalFilename === '' || !part.mimetype) { // usado internamente, por favor, não substitua! form._handlePart(part); } }; ``` ### Arquivo ```ts export interface File { // O tamanho do arquivo enviado em bytes. // Se o arquivo ainda estiver sendo carregado (veja o evento `'fileBegin'`), // esta propriedade diz quantos bytes do arquivo já foram gravados no disco. file.size: number; // O caminho em que este arquivo está sendo gravado. Você pode modificar isso no evento `'fileBegin'` // caso você esteja insatisfeito com a forma como o formidable gera um caminho temporário para seus arquivos. file.filepath: string; // O nome que este arquivo tinha de acordo com o cliente de upload. file.originalFilename: string | null; // calculado com base nas opções fornecidas. file.newFilename: string | null; // O tipo mime deste arquivo, de acordo com o cliente de upload. file.mimetype: string | null; // Um objeto Date (ou `null`) contendo a hora em que este arquivo foi gravado pela última vez. // Principalmente aqui para compatibilidade com o [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/). file.mtime: Date | null; file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256' // Se o cálculo `options.hashAlgorithm` foi definido, você pode ler o resumo hexadecimal desta var (no final, será uma string) file.hash: string | object | null; } ``` #### file.toJSON() Este método retorna uma representação JSON do arquivo, permitindo que você `JSON.stringify()` o arquivo que é útil para registrar e responder a solicitações. ### Eventos #### `'progress'` Emitido após cada bloco de entrada de dados que foi analisado. Pode ser usado para rolar sua própria barra de progresso. **Aviso** Use isso apenas para a barra de progresso do lado do servidor. No lado do cliente, é melhor usar `XMLHttpRequest` com `xhr.upload.onprogress =` ```js form.on('progress', (bytesReceived, bytesExpected) => {}); ``` #### `'field'` Emitido sempre que um par campo/valor é recebido. ```js form.on('field', (name, value) => {}); ``` #### `'fileBegin'` Emitido sempre que um novo arquivo é detectado no fluxo de upload. Use este evento se desejar transmitir o arquivo para outro lugar enquanto armazena o upload no sistema de arquivos. ```js form.on('fileBegin', (formName, file) => { // acessível aqui // formName o nome no formulário () ou http filename para octetstream // file.originalFilename http filename ou null se houver um erro de análise // file.newFilename gerou hexoid ou o que options.filename retornou // file.filepath nome do caminho padrão de acordo com options.uploadDir e options.filename // file.filepath = CUSTOM_PATH // para alterar o caminho final }); ``` #### `'file'` Emitido sempre que um par campo/arquivo é recebido. `file` é uma instância de `File`. ```js form.on('file', (formname, file) => { // o mesmo que fileBegin, exceto // é muito tarde para alterar file.filepath // file.hash está disponível se options.hash foi usado }); ``` #### `'error'` Emitido quando há um erro no processamento do formulário recebido. Uma solicitação que apresenta um erro é pausada automaticamente, você terá que chamar manualmente `request.resume()` se você quiser que a requisição continue disparando eventos `'data'`. Pode ter `error.httpCode` e `error.code` anexados. ```js form.on('error', (err) => {}); ``` #### `'aborted'` Emitido quando a requisição foi abortada pelo usuário. Agora isso pode ser devido a um evento 'timeout' ou 'close' no soquete. Após este evento ser emitido, um O evento `error` seguirá. No futuro, haverá um 'timeout' separado evento (precisa de uma mudança no núcleo do nó). ```js form.on('aborted', () => {}); ``` #### `'end'` Emitido quando toda a solicitação foi recebida e todos os arquivos contidos foram liberados para o disco. Este é um ótimo lugar para você enviar sua resposta. ```js form.on('end', () => {}); ``` ### Helpers #### firstValues Obtém os primeiros valores dos campos, como pré 3.0.0 sem passar múltiplos em uma lista de exceções opcionais onde arrays de strings ainda são desejados (`