O upload de MP3 do Google Drive no Android pode apresentar falhas em aplicações web desenvolvidas com Node.js e Multer, mesmo quando o envio de arquivos armazenados diretamente no celular funciona normalmente. Uma alternativa é criar uma cópia temporária do arquivo no navegador, enviá-la por meio do FormData e liberar a referência após a conclusão. Neste tutorial, veremos como implementar essa abordagem, identificar possíveis erros e validar o recebimento no servidor.
Por que o upload de MP3 do Google Drive pode falhar no Android?
Em aplicações web, o upload de arquivos normalmente utiliza um campo HTML do tipo file. Quando o usuário seleciona um MP3 armazenado no próprio dispositivo, o navegador geralmente consegue acessar seu conteúdo e enviá-lo ao servidor.
Entretanto, quando o arquivo é selecionado diretamente do Google Drive, o processo pode ser diferente. O Android utiliza mecanismos de seleção de documentos que permitem acessar arquivos disponibilizados por aplicativos e serviços de armazenamento em nuvem.
Nesse cenário, o Google Drive pode precisar disponibilizar ou transferir o conteúdo do arquivo antes que o navegador consiga utilizá-lo.
Dependendo do navegador, da implementação do formulário e da disponibilidade do arquivo, o upload pode falhar antes mesmo de chegar ao servidor Node.js.
Entre as possíveis causas estão:
- Falha ao disponibilizar o conteúdo do arquivo selecionado no Google Drive.
- Problemas na leitura do arquivo pelo navegador.
- Validação incorreta do tipo MIME do MP3.
- Limites de tamanho configurados no Multer ou no servidor web.
- Problemas na construção ou no envio do FormData.
- Interrupções de conexão durante o upload.
Importante: a seleção de um arquivo do Google Drive não significa necessariamente que o problema esteja no Multer. É necessário identificar em qual etapa a falha acontece.
Como diagnosticar o problema antes de alterar o código
O primeiro teste consiste em verificar se o navegador consegue ler o arquivo selecionado.
Considere um formulário com um campo de upload identificado como arquivo.
Adicione temporariamente o seguinte JavaScript:
document.getElementById('arquivo')
.addEventListener('change', async function () {
const arquivo = this.files[0];
if (!arquivo) {
return;
}
console.log('Nome:', arquivo.name);
console.log('Tamanho:', arquivo.size);
console.log('Tipo MIME:', arquivo.type);
try {
const conteudo = await arquivo.arrayBuffer();
console.log(
'Arquivo lido com sucesso:',
conteudo.byteLength,
'bytes'
);
} catch (erro) {
console.error(
'Erro ao ler o arquivo:',
erro
);
}
});
Execute esse teste no Android, selecionando primeiro um MP3 da pasta Downloads e depois um arquivo do Google Drive.
Se a leitura funcionar nas duas situações, mas o upload falhar apenas com o Drive, será necessário investigar a construção do FormData, o envio da requisição e o processamento no servidor.
Se o método arrayBuffer() apresentar erro, o problema ocorre antes de o Multer receber o arquivo.
Como funciona a solução com cópia temporária do MP3?
A solução consiste em criar um novo objeto File no navegador a partir do conteúdo do arquivo selecionado.
Esse novo arquivo será mantido temporariamente em memória e utilizado no envio ao servidor.
O processo segue estas etapas:
- O usuário seleciona um MP3 no Google Drive, Downloads ou outro local.
- O JavaScript obtém o conteúdo do arquivo selecionado.
- Uma cópia temporária é criada utilizando a API File.
- O arquivo temporário é adicionado ao FormData.
- O navegador envia o FormData para a aplicação Node.js.
- O Multer recebe e armazena o arquivo no servidor.
- Após a confirmação do envio, o JavaScript libera a referência à cópia temporária.
Essa abordagem permite padronizar a preparação do arquivo antes do upload, independentemente de sua origem.
Atenção: criar uma cópia temporária não garante a correção de todas as falhas relacionadas ao Google Drive. Se o navegador não conseguir acessar o conteúdo original, também não conseguirá criar a cópia.
Passo 1: criar o formulário HTML para upload de MP3
Crie um arquivo chamado index.html com um formulário para selecionar e enviar o MP3.
O formulário terá um campo para selecionar o arquivo, um botão para iniciar o upload e uma área para exibir o resultado da operação.
Upload de MP3
Enviar arquivo MP3
O atributo accept orienta o seletor de arquivos a apresentar formatos compatíveis com MP3. Entretanto, ele não substitui a validação no servidor.
Passo 2: criar a cópia temporária do arquivo com JavaScript
Crie o arquivo upload.js no mesmo diretório do formulário.
O código abaixo lê o arquivo selecionado, cria uma cópia temporária e envia essa cópia utilizando Fetch e FormData.
const inputArquivo = document.getElementById('arquivo');
const formulario = document.getElementById('formUpload');
const botaoEnviar = document.getElementById('btnEnviar');
const mensagem = document.getElementById('mensagem');
let arquivoTemporario = null;
let preparando = false;
let enviando = false;
let selecaoAtual = 0;
inputArquivo.addEventListener('change', async function () {
const selecao = ++selecaoAtual;
arquivoTemporario = null;
const arquivoOriginal = this.files[0];
if (!arquivoOriginal) {
mensagem.textContent = '';
return;
}
preparando = true;
botaoEnviar.disabled = true;
mensagem.textContent = 'Preparando arquivo...';
try {
if (!arquivoOriginal.name.toLowerCase().endsWith('.mp3')) {
throw new Error('Selecione um arquivo MP3.');
}
const conteudo = await arquivoOriginal.arrayBuffer();
if (selecao !== selecaoAtual) {
return;
}
arquivoTemporario = new File(
[conteudo],
arquivoOriginal.name,
{
type: 'audio/mpeg',
lastModified: Date.now()
}
);
mensagem.textContent = 'Arquivo pronto para envio.';
console.log({
nome: arquivoTemporario.name,
tamanho: arquivoTemporario.size,
tipo: arquivoTemporario.type
});
} catch (erro) {
if (selecao === selecaoAtual) {
arquivoTemporario = null;
mensagem.textContent = erro.message;
console.error('Erro ao preparar MP3:', erro);
}
} finally {
if (selecao === selecaoAtual) {
preparando = false;
botaoEnviar.disabled = enviando;
}
}
});
formulario.addEventListener('submit', async function (evento) {
evento.preventDefault();
if (preparando || enviando) {
return;
}
if (!arquivoTemporario) {
mensagem.textContent = 'Selecione um MP3 válido.';
return;
}
const formData = new FormData();
formData.append(
'arquivo',
arquivoTemporario,
arquivoTemporario.name
);
enviando = true;
botaoEnviar.disabled = true;
inputArquivo.disabled = true;
mensagem.textContent = 'Enviando arquivo...';
try {
const resposta = await fetch('/upload', {
method: 'POST',
body: formData
});
const resultado = await resposta.json();
if (!resposta.ok) {
throw new Error(
resultado.mensagem || 'Falha no upload.'
);
}
mensagem.textContent = 'MP3 enviado com sucesso!';
arquivoTemporario = null;
selecaoAtual++;
formulario.reset();
} catch (erro) {
mensagem.textContent = erro.message;
console.error('Erro no upload:', erro);
} finally {
enviando = false;
inputArquivo.disabled = false;
botaoEnviar.disabled = preparando;
}
});
Por que utilizar arrayBuffer()?
O método arrayBuffer() permite ler o conteúdo binário do arquivo selecionado.
Depois da leitura, o construtor File cria um novo objeto com os dados obtidos.
Isso permite preparar uma cópia independente para o envio, em vez de utilizar diretamente a referência original do campo de seleção.
Entretanto, o método carrega o conteúdo completo em memória. Em dispositivos Android com pouca memória disponível, arquivos grandes podem causar lentidão ou falhas.
Por esse motivo, a técnica deve ser utilizada considerando o tamanho máximo dos arquivos aceitos pela aplicação.
Por que não definir Content-Type manualmente no Fetch?
Ao enviar um FormData, o navegador configura automaticamente o cabeçalho multipart/form-data e o delimitador necessário para separar os campos da requisição.
Não configure manualmente esse cabeçalho no Fetch, pois a ausência ou inconsistência do delimitador pode impedir o Multer de interpretar corretamente o arquivo recebido.
Passo 3: configurar o Multer no Node.js
No backend, utilizaremos Express e Multer para receber o MP3 enviado pelo navegador.
Instale as dependências no projeto:
npm install express multer
Crie o arquivo server.js:
const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const app = express();
const PORT = process.env.PORT || 3000;
const pastaUploads = path.join(__dirname, 'uploads');
fs.mkdirSync(pastaUploads, {
recursive: true
});
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, pastaUploads);
},
filename: function (req, file, cb) {
const nomeSeguro = crypto.randomUUID() + '.mp3';
cb(null, nomeSeguro);
}
});
const upload = multer({
storage: storage,
limits: {
fileSize: 50 * 1024 * 1024,
files: 1
},
fileFilter: function (req, file, cb) {
const extensao = path.extname(
file.originalname
).toLowerCase();
if (extensao !== '.mp3') {
return cb(
new Error('Apenas arquivos MP3 são permitidos.')
);
}
cb(null, true);
}
});
app.use(express.static(
path.join(__dirname, 'public')
));
app.post('/upload', function (req, res) {
upload.single('arquivo')(req, res, function (erro) {
if (erro) {
if (erro instanceof multer.MulterError) {
return res.status(400).json({
sucesso: false,
mensagem: erro.message
});
}
return res.status(400).json({
sucesso: false,
mensagem: erro.message
});
}
if (!req.file) {
return res.status(400).json({
sucesso: false,
mensagem: 'Nenhum arquivo recebido.'
});
}
res.json({
sucesso: true,
mensagem: 'Upload realizado com sucesso.',
arquivo: req.file.filename,
tamanho: req.file.size
});
});
});
app.listen(PORT, function () {
console.log(
'Servidor iniciado na porta ' + PORT
);
});
Nesse exemplo, o Multer utiliza armazenamento em disco e limita cada arquivo a 50 MB.
O nome do arquivo armazenado é gerado pelo servidor, evitando utilizar diretamente o nome enviado pelo usuário como caminho de gravação.
Observação de segurança: o exemplo valida a extensão para demonstrar o funcionamento do upload, mas essa verificação não confirma que o conteúdo seja realmente um MP3. Em produção, implemente também uma validação do formato real do áudio antes de disponibilizar ou processar o arquivo. Arquivos rejeitados após a gravação devem ser removidos do armazenamento.
Passo 4: organizar os arquivos da aplicação
Para executar o exemplo, organize o projeto da seguinte forma:
projeto-upload/
|
|-- server.js
|-- package.json
|
|-- public/
| |-- index.html
| |-- upload.js
|
|-- uploads/
O diretório public contém os arquivos utilizados pelo navegador.
O diretório uploads armazena os arquivos recebidos pelo Multer e não deve ser exposto diretamente como conteúdo público sem controles adicionais.
Para iniciar o servidor:
node server.js
Em um ambiente local, abra o navegador e acesse:
http://localhost:3000
Para testar pelo Android, utilize um endereço de rede acessível pelo celular, considerando as configurações de rede e firewall do ambiente.
Como validar o upload de MP3 do Google Drive no Android
Depois de implementar a solução, execute os seguintes testes:
- Abra a aplicação no navegador do Android.
- Selecione um MP3 armazenado na pasta Downloads.
- Verifique se a mensagem “Arquivo pronto para envio” aparece.
- Envie o arquivo e confirme o retorno de sucesso.
- Repita o procedimento selecionando um MP3 diretamente do Google Drive.
- Confira se o servidor recebeu o arquivo e se ele pode ser reproduzido corretamente.
Quando o upload funcionar, o servidor deverá retornar uma resposta JSON semelhante a esta:
{
"sucesso": true,
"mensagem": "Upload realizado com sucesso.",
"arquivo": "nome-gerado-pelo-servidor.mp3",
"tamanho": 5242880
}
O nome e o tamanho apresentados acima são apenas exemplos. Os valores reais dependerão do arquivo enviado.
Também é importante verificar se a cópia temporária deixa de ser referenciada após o envio bem-sucedido.
No exemplo, isso acontece por meio da atribuição:
arquivoTemporario = null;
formulario.reset();
Essa operação libera a referência mantida pela aplicação e limpa o formulário. A recuperação efetiva da memória é gerenciada automaticamente pelo navegador.
O arquivo original armazenado no Google Drive não é apagado.
Problemas comuns ao utilizar cópias temporárias no upload
O arquivo do Google Drive não pode ser lido
Se arquivo.arrayBuffer() apresentar erro, o navegador não conseguiu obter o conteúdo necessário para criar a cópia.
Nesse caso, teste o download do MP3 para o armazenamento local do Android e tente selecioná-lo novamente.
Se o arquivo local funcionar, investigue o comportamento do seletor de arquivos, do navegador e do aplicativo Google Drive.
O Multer retorna LIMIT_FILE_SIZE
Esse erro indica que o arquivo ultrapassou o limite configurado no Multer.
No exemplo apresentado, o limite é de 50 MB:
limits: {
fileSize: 50 * 1024 * 1024
}
Ajuste o valor somente quando necessário, considerando a capacidade do servidor e as regras da aplicação.
O arquivo é enviado, mas o servidor não o reconhece
Verifique se o nome utilizado no FormData corresponde ao campo esperado pelo Multer.
No frontend:
formData.append('arquivo', arquivoTemporario);
No backend:
upload.single('arquivo')
Os nomes devem ser iguais. Caso contrário, o Multer poderá rejeitar o campo enviado.
O arquivo possui um tipo MIME diferente
Arquivos MP3 normalmente utilizam o tipo MIME audio/mpeg, mas o valor informado pelo navegador pode variar conforme a origem do arquivo.
O exemplo atribui audio/mpeg à cópia criada, mas isso apenas define o metadado do objeto File. Não converte nem valida o conteúdo do áudio.
Para uma aplicação em produção, não utilize exclusivamente o MIME informado pelo cliente para decidir se o arquivo é seguro ou válido.
O upload funciona no computador, mas falha no Android
Compare os testes entre navegadores e verifique se o problema acontece somente com arquivos selecionados da nuvem.
Também confira os logs do Node.js e as respostas HTTP da requisição de upload.
Se nenhuma requisição chegar ao servidor, o problema provavelmente está na seleção, preparação ou transmissão inicial do arquivo.
Alternativa para arquivos MP3 grandes
O uso de arrayBuffer() pode consumir uma quantidade significativa de memória, especialmente quando o arquivo possui dezenas de megabytes.
Uma alternativa é construir um novo File utilizando o objeto original como fonte:
const arquivoOriginal = inputArquivo.files[0];
const copia = new File(
[arquivoOriginal],
arquivoOriginal.name,
{
type: arquivoOriginal.type || 'audio/mpeg'
}
);
const formData = new FormData();
formData.append('arquivo', copia);
Essa abordagem evita a leitura explícita do arquivo inteiro para um ArrayBuffer no JavaScript.
Entretanto, o navegador ainda poderá precisar acessar ou materializar os dados durante o envio. Portanto, a alternativa não garante a correção de problemas de leitura de arquivos provenientes do Google Drive.
Para uploads grandes ou conexões instáveis, também pode ser interessante avaliar mecanismos de envio em partes e retomada de transferências.
Resumo prático
Falhas no upload de MP3 do Google Drive no Android podem ocorrer antes de o arquivo chegar ao Node.js, especialmente quando o navegador encontra dificuldades para obter o conteúdo disponibilizado pelo serviço de armazenamento.
Uma abordagem possível é criar uma cópia temporária com JavaScript, enviá-la utilizando FormData e deixar o Multer responsável pelo recebimento no backend.
Após a confirmação do upload, a aplicação pode liberar a referência ao arquivo temporário e limpar o formulário, sem modificar o MP3 original armazenado no Google Drive.
Antes de aplicar essa solução como correção definitiva, confirme que o navegador consegue ler o arquivo original. Também considere o consumo de memória, os limites de upload e a validação real do formato MP3 no servidor.