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

人人网开放平台、新浪微博开放平台、腾讯开放平台中,照片上传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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值