Como enviar objects FormData com solicitações Ajax no jQuery?

O padrão XMLHttpRequest Nível 2 (ainda um rascunho de trabalho) define a interface FormData . Essa interface permite append objects File a solicitações XHR (solicitações Ajax).

Btw, este é um novo recurso – no passado, o “hidden-iframe-trick” foi usado (leia sobre isso na minha outra pergunta ).

É assim que funciona (exemplo):

 var xhr = new XMLHttpRequest(), fd = new FormData(); fd.append( 'file', input.files[0] ); xhr.open( 'POST', 'http://example.com/script.php', true ); xhr.onreadystatechange = handler; xhr.send( fd ); 

onde input é um campo , e handler é o manipulador de sucesso para o pedido Ajax.

Isso funciona lindamente em todos os navegadores (novamente, exceto o IE).

Agora, gostaria de fazer essa funcionalidade funcionar com o jQuery. Eu tentei isso:

 var fd = new FormData(); fd.append( 'file', input.files[0] ); $.post( 'http://example.com/script.php', fd, handler ); 

Infelizmente, isso não funcionará (um erro “Invocação ilegal” é acionado – a captura de canvas está aqui ). Eu suponho que o jQuery espera um object simples de valor-chave representando nomes / valores de campos de formulário, e a instância de FormData que estou passando é aparentemente incompatível.

Agora, como é possível passar uma instância de FormData para xhr.send() , espero que também seja possível fazê-lo funcionar com jQuery.


Atualizar:

Eu criei um “ticket de recurso” no Bug Tracker do jQuery. Está aqui: http://bugs.jquery.com/ticket/9995

Eu fui sugerido para usar um “prefilter Ajax” …


Atualizar:

Primeiro, deixe-me dar uma demonstração demonstrando qual comportamento eu gostaria de alcançar.

HTML:

     

JavaScript:

 $( 'form' ).submit(function ( e ) { var data, xhr; data = new FormData(); data.append( 'file', $( '#file' )[0].files[0] ); xhr = new XMLHttpRequest(); xhr.open( 'POST', 'http://hacheck.tel.fer.hr/xml.pl', true ); xhr.onreadystatechange = function ( response ) {}; xhr.send( data ); e.preventDefault(); }); 

O código acima resulta nesta solicitação HTTP:

multipartformdata

Isto é o que eu preciso – eu quero esse tipo de conteúdo “multipart / form-data”!


A solução proposta seria assim:

 $( 'form' ).submit(function ( e ) { var data; data = new FormData(); data.append( 'file', $( '#file' )[0].files[0] ); $.ajax({ url: 'http://hacheck.tel.fer.hr/xml.pl', data: data, processData: false, type: 'POST', success: function ( data ) { alert( data ); } }); e.preventDefault(); }); 

No entanto, isso resulta em:

wrongcontenttype

Como você pode ver, o tipo de conteúdo está errado …

Eu acredito que você poderia fazer assim:

 var fd = new FormData(); fd.append( 'file', input.files[0] ); $.ajax({ url: 'http://example.com/script.php', data: fd, processData: false, contentType: false, type: 'POST', success: function(data){ alert(data); } }); 

Definir processData como false permite evitar que o jQuery transforme automaticamente os dados em uma string de consulta. Veja os documentos para mais informações.

Configurar o contentType para false é imperativo, pois caso contrário o jQuery irá configurá-lo incorretamente .

Existem algumas técnicas ainda a serem mencionadas disponíveis para você. Comece com a configuração da propriedade contentType em seus parâmetros do ajax.

Com base no exemplo do pradeek:

 $('form').submit(function (e) { var data; data = new FormData(); data.append('file', $('#file')[0].files[0]); $.ajax({ url: 'http://hacheck.tel.fer.hr/xml.pl', data: data, processData: false, type: 'POST', // This will override the content type header, // regardless of whether content is actually sent. // Defaults to 'application/x-www-form-urlencoded' contentType: 'multipart/form-data', //Before 1.5.1 you had to do this: beforeSend: function (x) { if (x && x.overrideMimeType) { x.overrideMimeType("multipart/form-data"); } }, // Now you should be able to do this: mimeType: 'multipart/form-data', //Property added in 1.5.1 success: function (data) { alert(data); } }); e.preventDefault(); }); 

Em alguns casos, ao forçar o ajax do jQuery a fazer coisas não esperadas, o evento beforeSend é um ótimo lugar para fazê-lo. Por um tempo as pessoas estavam usando beforeSend para replace o mimeType antes que ele fosse incluído no jQuery no 1.5.1. Você deve ser capaz de modificar praticamente qualquer coisa no object jqXHR no evento before send.

Você pode enviar o object FormData na solicitação ajax usando o seguinte código,

 $("form#formElement").submit(function(){ var formData = new FormData($(this)[0]); }); 

Isso é muito semelhante à resposta aceita, mas uma resposta real para o tópico da pergunta. Isso enviará os elementos do formulário automaticamente no FormData e você não precisará append manualmente os dados à variável FormData.

O método ajax se parece com isso,

 $("form#formElement").submit(function(){ var formData = new FormData($(this)[0]); //append some non-form data also formData.append('other_data',$("#someInputData").val()); $.ajax({ type: "POST", url: postDataUrl, data: formData, processData: false, contentType: false, dataType: "json", success: function(data, textStatus, jqXHR) { //process data }, error: function(data, textStatus, jqXHR) { //process error msg }, }); 

Você também pode passar manualmente o elemento de formulário dentro do object FormData como um parâmetro como este

 var formElem = $("#formId"); var formdata = new FormData(form[0]); 

Espero que ajude. 😉

Você pode usar o evento $ .ajax beforeSend para manipular o header.

 beforeSend: function(xhr) { xhr.setRequestHeader('Content-Type', 'multipart/form-data'); } 

Veja este link para informações adicionais: http://msdn.microsoft.com/en-us/library/ms536752(v=vs.85).aspx

Eu acho que você não pode fazê-lo em ajax para suportar todos os navegadores, eu poderia dizer bom para verificar este plugin ajax uploader para ver como eles fizeram isso http://valums.com/ajax-upload/

Eu faço assim e é trabalho para mim, espero que isso ajude 🙂

  


Se você quiser enviar arquivos usando o ajax, use “jquery.form.js”. Isso envia todos os elementos do formulário facilmente.

Amostras http://jquery.malsup.com/form/#ajaxSubmit

visão áspera:

 

  

JavaScript:

  function submitForm() { var data1 = new FormData($('input[name^="file"]')); $.each($('input[name^="file"]')[0].files, function(i, file) { data1.append(i, file); }); $.ajax({ url: "employee/dashboard2/test2", type: "POST", data: data1, enctype: 'multipart/form-data', processData: false, // tell jQuery not to process the data contentType: false // tell jQuery not to set contentType }).done(function(data) { console.log("PHP Output:"); console.log( data ); }); return false; } 

PHP:

 public function upload_file(){ foreach ($_FILES as $key ) { $name =time().$key['name']; $path='upload/'.$name; @move_uploaded_file($key['tmp_name'],$path); } 

Em vez de – fd.append( 'userfile', $('#userfile')[0].files[0]);

Use – fd.append( 'file', $('#userfile')[0].files[0]);

A melhor documentação e exemplo que encontrei foi aqui https://developer.mozilla.org/en-US/docs/Web/Guide/Using_FormData_Objects