您的位置:首页 > 其它

[开发手记] 人人网开放平台不使用表单上传照片

2012-06-26 15:27 351 查看
人人网开放平台、新浪微博开放平台、腾讯开放平台中,照片上传API均要求采用采用multipart/form-data编码方式提交。但是在有些场合中,用表单获取文件是一件比较困难的事情,比如在客户端上,用 Canvas 生成了一幅图片,希望把它上传到以上社交网络的相册该怎么办呢?

第一种方法是使用显式的表单,将 Canvas 生成的图片保存到本地,具体操作方法见我的另一篇博客如何将Canvas中的内容保存为本地图片。然后使用
<input type=”file”> 控件,载入这幅图片,并上传到人人网,就像人人网开放平台提供的 JavaScript SDK 一样。

但是这种方法存在一个问题,根据W3C标准,<input type=”file”> 这个对象的 value 属性是只读的,也就是说,不能通过 JavaScript 来改变其值。参见W3School的FileUpload对象的教程,为安全起见,FileUpload对象不允许HTML作者和JavaScript程序员设定value值,也就是说,这个值必须由用户手动指定。这样,使用这种方法就彻底断绝了一键自动上传的技术路径。

那么该怎么办呢,参阅人人网的技术文档之后,认为唯一的出路就是模拟multipart
/ form-data请求,那么如何才能模拟该请求呢? 我想到了ajax。

但是ajax也彻底断绝了这条技术道路,ajax基于XMLHTTPRequest技术,而这项技术的很大一个遗憾就是无法传送文件。就在我走投无路的时候,知乎上一位高人指点:用XML
HTTP Request Level 2。

XMLHttpRequest Level 2是HTML5的新特性,其目的就是弥补XMLHttpRequest在文件传输中的不足。以往使用XMLHttpRequest来传送文件都是使用overrideMimeType()来欺骗浏览器达到传送二进制文件的目的。但是使用Level 2就不需要这样藏着掖着了,Level 2在send()方法中添加了许多对文件的支持,比如:

void send();

void send(ArrayBuffer data);

void send(Blob data);

void send(Document data);

void send(DOMString? data);

void send(FormData data);

其中,FormData是一个Level 2新支持的接口,它允许发送key-value对数据,同时允许这些数据可以是文件,请求格式即multipart/form-data。

FormData的使用方法如下:

fd = new FormData();

fd.append(name, value, [filename]);

处理append方法是这样进行的:先将name赋值;再将value赋值;如果value的类型是字符串,那么就将键值对的type设为text,如果是Blob(参见HTML5的BlobBuilder),则将键值对的type设为file; 如果类型是file,用这种规则定义文件名,优先为filename字段,如果为空,则为Blob的文件名,如果为空,则为’blob’。

最后使用XMLHttpRequest对象req时,只需要使用:

req.send(fd);

这么轻松就解决问题了,下面上实际代码:

renren.authorize(function(){

access_token = renren.getAccessToken();

if (window.console) {

console.log(access_token);

}

// 下列代码是为了产生sig

var params = {};

params['access_token'] = access_token;

params['call_id'] = new Date().valueOf();

params['method'] = "photos.upload";

params['v'] = "1.0";

params['format'] = "json";

params['caption'] = caption;

var param_array = [];

//遍历表单中调用接口需要的参数,并拼装成"key=value"形式压入数组

for (var key in params){

param_array.push(key + "=" + params[key]);

}

// 下列函数 generateSigFromArray 来自人人网的demo

var sig = generateSigFromArray(param_array, secret_key);

params['sig'] = sig;

// 定义FormData

var myForm = new FormData();

// 从 Canvas 中取得数据,dataURItoBlob()见上一篇博客

var canvas = $("#canvas")[0];

var canvasToDataURL = canvas.toDataURL('image/png');

var bb = dataURItoBlob(canvasToDataURL);

myForm.append('method', params['method']);

myForm.append('access_token', params['access_token']);

myForm.append('call_id', params['call_id']);

myForm.append('v', params['v']);

myForm.append('caption', params['caption']);

myForm.append('format', params['format']);

myForm.append('sig', params['sig']);

// append一个文件

myForm.append('upload', bb, 'renren.png');

// 定义一个 XMLHttpRequest 对象

var req = new XMLHttpRequest();

req.open("POST", "http://api.renren.com/restserver.do", true);

req.onreadystatechange = RequestCallBack;

req.send(myForm);

function RequestCallBack(){

if (req.readyState == 4){//DONE

// 此处可以查看 req.status 和req.response 并进行处理了。

}

}

}

参考文档:

XMLHttpRequest,
Editor’s Draft 14 May 2012

XMLHttpRequest,
MDN

FormData,
MDN
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐