最近在作一个音乐webapp的时候,遇到这样一个需求:提取歌曲图片的主题色,而后应用到全局。
一开始的思路是把图片绘入到canvas中利用getImageData()获取图片的像素数据,分析这些数据得出最接近图片的颜色。接着问题来了,若是在canvas绘入跨域资源,canvas将受到污染,没法调用方法(由于数据都是在QQ音乐官网抓取的)。说到这,咱们就说说前端跨域的那些事。
对项目感兴趣的点这里👉项目地址前端
通常来讲,当一个请求url的协议、域名、端口三者之间任意一个与当前页面地址不一样即为跨域。最多见的就是在一个域名下的网页中,调用另外一个域名中的资源。
当浏览器报这样的错的时候,就是跨域请求出问题了
java
主要是为了安全,浏览器采用同源策略,对js进行限制,防止恶意用户获取非法数据,同时还防止了大部分XSS攻击(就是向用户界面注入js脚本)。
浏览器的两种同源策略会形成跨域问题:web
这是由于W3C推出的了一个标准----"跨域资源共享"(Cross-origin resource sharing),简称CORS。该标准定义了跨域访问资源时服务器和浏览器怎么通讯。通俗讲就是浏览器在发现跨域请求的时候会附加一些头信息和服务器进行沟通,来肯定跨域请求通不经过。如今除IE10如下的浏览器都支持这个标准。
浏览器会把跨域请求分红两类:简单和非简单请求。express
简单请求有如下特征:npm
同时知足以上两点的就是简单请求,其余就是非简单请求了。
当浏览器把跨域请求识别为简单请求的时候,就会在头信息里附加上一个Origin字段,该字段会把此次请求的来源(协议、域名、端口)带给服务器,服务器就会检查这个请求的来源。
要是服务器赞成了这个来源呢,在正常回复浏览器的同时,就也附加上几条字段做为回礼:json
要是不一样意,服务器就正常返回数据,啥也不附加,浏览器见不到Access-Control-Allow-Origin会不高兴的,而后就不给你返回的数据了,再而后就是报错,这个错就是上面那这样的(就是提取颜主题色的时候😡)。 并且状态码仍是各类各样的,甚至有多是200😫canvas
这种不简单的请求,好比PUT或DELETE请求,还有 Content-Type字段类型为
application/json的。浏览器会严格一点,在发跨域请求前,会发个“预检”请求看看服务器的态度先,这个预检请求比较特殊,请求方式叫OPTIONS,头信息里不光有Origin字段还有这俩:后端
服务器收到预检请求提交过来的信息后,也会严格一点,不只检查来源,还检查请求方式和头信息字段。
要是服务器赞成了,就在正常的HTTP回应中附加上Access-Control-Allow-Origin字段,也一样写着服务赞成的来源。
这就表明这拿到服务器的承认了,毕竟是经历过严格检查的,接下来的每次跨域请求都会正常进行。
要是不一样意,服务器也是啥都不附加地正常回应,这个时候浏览器看不见Access-Control-Allow-Origin但是会生气的,连跨域请求都懒得发,直接报错。(这种状况还没碰到,就不上图啦)。
因此说报错是浏览器搞得鬼。api
平常开发中会常常碰到跨域的问题,咱们来看看常见的解决方法:跨域
像img、script等标签是没有跨域限制的,因而乎程序猿们就想到一个办法,动态建立script标签,经过src属性来进行跨域请求的来源
function fun(data) {
console.log(data);
};
var body = document.getElementsByTagName('body')[0];
var script = document.gerElement('script');
script.type = 'text/javasctipt';
script.src = 'http://example.com?jsonp=cb';
body.appendChild(script);复制代码
返回的js脚本会直接执行,这样咱们想要的数据就传了进来。
这种方法全部浏览器都兼容,前端能够很轻松的作到跨域请求,但也有一些缺点:
本文的需求是要把图片绘入到canvas里,这个方法就行不通了,看下一种
服务器不像浏览器那样有跨域限制,可让服务器去请求跨域资源而后再返回给客户端,就拿canvas操做跨域图片来讲,客户端把跨域的url传给服务器,请求到图片后再传回客户端,就能够解决开头说到的那个问题了(上代码啦~)
图片是以二进制流的方式在http协议中传输,因此必定要注意编码格式,不然就返回一堆不知道是啥的东西啦
首先在后台起一个express服务,这里的get请求用的是npm中的https包
apiRoutes.get('/image', function (req, res) {
const Url = (req.query)['0'];
https.get(Url, function (response) {
response.setEncoding('binary'); //二进制binary
var type = response.headers["content-type"];
let Data = '';
response.on('data', function (data) { //加载到内存
Data += data;
}).on('end', function () { //加载完
res.writeHead(200, { 'Access-Control-Allow-Origin': '*', "Content-Type": type }); //设置头,容许跨域
res.end(new Buffer(Data, 'binary'));
})
})
});
app.use('/api', apiRoutes)复制代码
而后把跨域的图片url提交到这个路由上,就能够‘假装’成同源图片啦
http://example.com/api/image?0=(跨域的图片url)复制代码
—————————————— 更新 11.17 ————————————————
关于主题色的提取在这里👉主题色提取
以上即是此次的文章分享了,欢迎留言相互学习~