您的位置:首页 > 理论基础 > 计算机网络

Ajax获取图片的两种方式

2017-08-10 21:00 363 查看
在Web项目中,我们可能遇到需要利用Ajax来获取图片的情况。因为客户端处理的是图片文件的二进制流,所以可利用Blob和File API来将图片转为URL,赋值给img的src属性来解决这个问题。本文总结Ajax获取图片的两种方式,即针对XMLHttpRequest Level 1和Level 2给出解决方案。(注意:若无说明,下文中所有xhr都代表XMLHttpRequest 对象)。PS:最近想到这种需求,于是阅读一些资料,整了一天,写了本篇文章。如有错误,请不吝指正。题外话:写博客贵在坚持呀!!!

首先给出html结构,因为重点讲Ajax,所以用一个很简单的例子来说明,页面只有一个button和一个img。

<!--login.html的其他代码省略 -->
<input type="button" id="btn">
<!--获取的图片将在此显示-->
<img id="preview">


因为Ajax要和后台交互,此处将使用Node.js完成后台的逻辑,逻辑同样很简单。只需对
/
/upload
做处理即可。Ajax将请求
/upload
的内容。当请求时,发送给客户端图片。代码如下:

var http=require('http');
var fs=require('fs');
http.createServer((req,res)=>{
console.log(`${req.method}:${req.url}`);
if(req.url=='/'){
res.writeHead(200,{'Content-Type':'text/html,charset=utf-8'});
fs.createReadStream('login.html').pipe(res);
}else if(req.url=='/upload'){
if(req.method.toLowerCase()=='get'){
fs.readFile('images/captcha.0953f.png',(err,file)=>{
res.setHeader('Content-Length',file.length);
console.log(file.length);
res.writeHead(200,{'Content-Type':'image/png'});
res.end(file);
})
}else{
res.end('success');
}
}else{
fs.readFile('.'+req.url,(err,file)=>{
if(err){
res.writeHead(404);
res.end('Not found!');
}
fs.createReadStream('.'+req.url).pipe(res);
})
}
}).listen(3000);


Ajax请求图片的两种方式

首先公共代码如下:

window.onload=function(){
var btn=document.getElementById('btn');
btn.onclick=function(){
sendRequest();
}
}


XMLHttpRequest level 1(兼容旧浏览器):利用
overrideMimeType()
方法,将xhr设置为
xhr.overrideMimeType('text/plain;charset=x-user-defined');
。其中
text/plain
表示把响应作为普通文本来处理;
charset=x-user-defined
表示使用用户自定义的字符集,以告诉浏览器不要去解析数据,直接返回未处理过的字节码。此步骤必须,不可忽略。之后就可以通过
xhr.responseText
取得响应文本,然后将其转为二进制数据,传递给Blob构造函数。而后,通过
FileReader
readAsDataURL()
方法创建URL赋值给图片的src属性即可。具体代码如下:

function sendRequest(){
var xhr=new XMLHttpRequest();
xhr.onload=function(){
if(xhr.status>=200 && xhr.status<300){
var binStr = this.responseText;
//console.log(this.response==this.responseText);//true
var arr = new Uint8Array(binStr.length);
for(var i = 0, l = binStr.length; i < l; i++) {

arr[i] = binStr.charCodeAt(i);
//arr[i] = binStr.charCodeAt(i) & 0xff;
}
//console.log(binStr.charCodeAt(0).toString(16));
//console.log(arr[0].toString(16));
var blob=new Blob([arr.buffer],{type:'image/png'})
loadImage_file(blob);
}else{
console.log('error');
}
}
xhr.open('get','/upload',true);
//兼容老浏览器。必须,以文本格式接受,字符集自定义
xhr.overrideMimeType('text/plain;charset=x-user-defined');
xhr.send(null);
}
function loadImage_file(blob){
var fr=new FileReader();
fr.readAsDataURL(blob);
fr.onload=function(e){
var preview=document.getElementById('preview');
preview.src=e.target.result;
}
}


该方法关键点是把响应文本转为二进制数据,利用字符串的
charCodeAt(index)
方法可以得到index位置的字符码,遍历整个字符串将其编码保存至
Uint8Array
中,而后传递给Blob来重构URL。关于
arr[i] = binStr.charCodeAt(i) & 0xff;
,表示在每个字符的两个字节之中,只保留后一个字节,将前一个字节扔掉。原因是浏览器解读字符的时候,会把字符自动解读成Unicode的0xF700-0xF7ff区段。
但因为我用的是
Uint8Array
,它会自动截取低8位,所以做不做与运算也就无所谓了。

XMLHttpRequest level 2:设置xhr的responseType属性,指定为
blob
(或
ArrayBuffer
,如设置为
ArrayBuffer
,还要转
Uint8Array
,然后转成
blob
),例如,
xhr.responseType='blob';
。这样就可以通过
xhr.response
来获取该blob对象。注意不能用
xhr.responseText
来获取,因为该属性只在响应类型是“text”时有效,强行获取只会得到错误:
Uncaught InvalidStateError: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob').
。该方法响应blob对象,所以无需对响应再做其他处理,只需传给
FileReader
readAsDataURL()
就可以了。代码如下:

function sendRequest(){
var xhr=new XMLHttpRequest();
xhr.onload=function(){
if(xhr.status>=200 && xhr.status<300){
var blob = this.response;
//loadImage_file()方法与前面相同
loadImage_file(blob);
}else{
console.log('error');
}
}
xhr.open('get','/upload',true);
xhr.responseType='blob';
xhr.send(null);
}


从中可以看出,代码量大大减少,语法简洁而清晰。

总结:两种方式各有各的有点,方法一兼容性好,方法二清晰简洁。具体用那种,还看各位的想法了。

最后,给出几篇关于XMLHttpRequest的优秀文章:

1. 你真的会使用XMLHttpRequest吗?

2. XMLHttpRequest Level 2 使用指南
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息