利用 FormData 对象发送 Key/Value 对的异步请求

使用Key/Value对和FormData能够轻易地通过XMLHttpRequest指定要传递什么数据,它是一个非常强大的发送数据到服务器的方法。
 
基础 

通常的方法是你创建一个 FormData 对象。然后你使用append方法来加入任何额外的key和他们的值。就像这样: 

view source
print?

1 var form = new FormData(); 
2 form.append("myName", "Robert"); 

然后你只需使用XMLHttpRequest(XHR)的send方法来发送: 


1 var xhrForm = new XMLHttpRequest(); 

2 xhrForm.open("POST", "getfile.php"); 

3 xhrForm.send(form); 

对于FormData,有趣的是不限制你加入字符串,但是实际上还有许多不同的类型 
• 字符串 
• 数字(发送的时候会转换为字符串) 
• 文件 
• 二进制对象(BLOB) 

要想能够在服务器端处理一个FormData的表单,要知道的重点是和一个multipart/form-data编码的常规表单一样发送。 
加入文件和二进制对象(blob) 

如果你想加入一个文件,最简单的方法是访问通过一个type="file"的输入元素选择的文件: 

1 form.append("theFile", fileInput.files[0]); 

加入一个二进制对象(blob) 

在发送和接收值方面,使用二进制对象(blob)是十分强大的。一个二进制对象(blob)可以手动通过它的内容或者类型的引用去创建: 


1 form.append("blobbie", new Blob([imgAsBlobRef], {"type": "image/png"})); 

创建你的二进制对象(blob)的内容: 

你也可以自己穿件一个二进制对象(blob)的内容: 

1 var xmlForBlob = ["Robert"], 
2     xmlBlob = new Blob(xmlForBlob, {"type" : "text/xml"}); 
3
4 form.append("xmlParts", xmlBlob); 

在页面上获取图像和创建二进制对象(blob) 

另外,你也可以在页面上通过XHR来获取一个图像然后通过FormData来发送: 

01 // Getting a file through XMLHttpRequest as an arraybuffer and creating a Blob 
02 var rhino = document.querySelector("#rhino"); 
03 if (rhino) { 
04     var xhr = new XMLHttpRequest(), 
05         blob;
06
07     xhr.open("GET", "rhino.png", true); 
08     xhr.responseType = "blob"; 
09
10     xhr.onreadystatechange = function () { 
11         if (xhr.readyState === 4 && xhr.status === 200) { 
12             blob = xhr.response; 
13             var form = new FormData(); 
14             form.append("blobbie", blob); 
15                
16             var xhrForm = new XMLHttpRequest(); 
17             xhrForm.open("POST", "getfile.php"); 
18             xhrForm.send(form); 
19         } 
20     }; 
21     // Send XHR 
22     xhr.send(); 
23 } 
使用Web Activity 
我以前在Mozilla Hacks博客上写过一篇关于Web Activities的文章, 使用里面的方法,你可以访问设备的相机,拍照,然后得到一个二进制对象(blob)的返回结果。 
一旦你获取到它(blob),你就可以把它发送到服务器。在这种情况下,我们会通关过Web Activity拍照,通过FormData发送二进制对象到服务器,然后从服务器获得返回的图像,截止在当前页面中呈现图片: 

01 var pick = new MozActivity({ 
02      name: "pick", 
03      data: { 
04          type: ["image/png", "image/jpg", "image/jpeg"] 
05      } 
06  }); 
07   
08 pick.onsuccess = function () {?    var form = new FormData(); 
09     form.append("blobbie",  this.result.blob); 
10
11     var xhrForm = new XMLHttpRequest(); 
12     xhrForm.open("POST", "getfile.php");
13     xhrForm.send(form); 
14
15     xhrForm.onreadystatechange = function () { 
16         if (xhrForm.readyState === 4) { 
17             var img = document.createElement("img"); 
18             img.src = xhrForm.response; 
19
20             var imagePresenter = document.querySelector("#image-presenter"); 
21             imagePresenter.appendChild(img); 
22             imagePresenter.style.display = "block"; 
23         } 
24     }; 
25 };<span><span style="line-height: 19px;"> </span></span> 
记得文章开头的地方我提到过的表单是在multipart/form-data的编码下发送。这里就是你怎样去读取通过FormData传送的名称、值和二进制对象的内容的方法: 
1 <?php 
2     $fileName = $_FILES['blobbie']['name']; 
3     $fileType = $_FILES['blobbie']['type']; 
4     $fileContent = file_get_contents($_FILES['blobbie']['tmp_name']); 
5     $dataURL = 'data:' . $fileType . ';base64,' . base64_encode($fileContent); 
6     echo $dataURL; 
7 ?> 

上面的代码是我在Eric Bidelman的一个gist里的发现的 。 通常,你应该能用任何的服务器端语言来做到这点。这里选择PHP,只是因为它已经在大多数服务器上运行了。 
一个完整的demo 

我把通过XHR获取一个在页面上的图像、通过FormData来传送它、读取内容以及返回一个图像能够再次显示在页面的URL放在了一个完整的例子中。 

一般来说,这是一个展示怎样来回发送消失的实践。 

可以在以下的URL中获取例子 https://github.com/robnyman/robnyman.github.com/tree/master/html5demos/formdata 

(大概由于一些原因,GitHub页面不能让你运行PHP代码来读取文件内容,但是在FormData GitHub page 里可以看到带有一个不完整图像的页面/布局)。 

 

JavaScript 代码 

01 (function () { 
02     // Getting a file through XMLHttpRequest as an arraybuffer and creating a Blob 
03     var rhino = document.querySelector("#rhino"); 
04     if (rhino) { 
05         var xhr = new XMLHttpRequest(), 
06             blob; 
07 
08         xhr.open("GET", "rhino.png", true); 
09         /* 
10             Set the responseType to "blob".  
11             If it isn't supported in the targeted web browser,  
12             use "arraybuffer" instead and wrap the response  
13             with new Uint8Array() below 
14         */ 
15         xhr.responseType = "blob"; 
16
17         xhr.onreadystatechange = function () { 
18             if (xhr.readyState === 4 && xhr.status === 200) {
19                 /*  
20                     Create a blob from the response 
21                     Only needed if the responseType isn't already blob 
22                     If it's "arraybuffer", do this: 
23
24                     blob = new Blob([new Uint8Array(xhr.response)], {type: "image/png"}); 
25                 */ 
26                 blob = xhr.response; 
27                 var form = new FormData(); 
28                 form.append("blobbie", blob); 
29
30                 var xhrForm = new XMLHttpRequest(); 
31                 xhrForm.open("POST", "getfile.php"); 
32                 xhrForm.send(form); 
33
34                 xhrForm.onreadystatechange = function () { 
35                     if (xhrForm.readyState === 4) { 
36                         console.log(xhrForm.response); 
37                         rhino.src = xhrForm.response; 
38                     } 
39                 }; 
40             } 
41         }; 
42         // Send XHR 
43         xhr.send(); 
44     } 
45 })(); 

PHP 代码 

1 <?php 
2     $fileName = $_FILES['blobbie']['name']; 
3     $fileType = $_FILES['blobbie']['type']; 
4     $fileContent = file_get_contents($_FILES['blobbie']['tmp_name']); 
5     $dataURL = 'data:' . $fileType . ';base64,' . base64_encode($fileContent);
6     echo $dataURL; 
7 ?> 

浏览器支持 

实际上真的好棒!支持FormData的浏览器有: 
•Firefox 4+ 
• Google Chrome 7+ 
• Safari 5+ 
• Opera 12+ 
• Internet Explorer 10+ (计划支持) 

支持二进制对象的浏览器有: 
•Firefox 13+ 
• Google Chrome 20+ 
• Safari 5.1+ 
• Opera 12.1+ 
• Internet Explorer 10+ (计划支持) 

 

posted @ 2013-09-13 12:14  如.若  阅读(1204)  评论(0编辑  收藏  举报