参考: HTTP访问控制(CORS)
当页面与页面请求的资源 不在 同一域/协议/端口
时,会发起一个 跨域HTTP请求
。php
出于安全缘由,浏览器会限制从脚本内发起的跨源HTTP请求或响应。html
经过跨域资源共享 CORS(cross-origin share standard) 机制,可以使跨域数据传输安全进行。canvas
HTTP请求头部字段跨域
头部 | 名称 | 说明 |
---|---|---|
Origin |
源站域名 | XMLHttpRequest跨域才发送 Image需标明 crossOrigin=anonymous/use-credentials 有些服务经过判断有没有Origin来决定是否展现受权相关的响应头部字段,例如阿里云OSS |
Access-Control-Request-Method |
实际请求的 HTTP 方法 | |
Access-Control-Request-Headers |
实际请求的携带的自定义头部字段名字 |
HTTP响应头部字段浏览器
头部 | 名称 | 说明 |
---|---|---|
Access-Control-Allow-Origin |
容许访问该资源的URI | * 或 http://example.com ; 若为附带身份凭证的请求,此处不能为 * |
Access-Control-Allow-Credentials |
是否容许附带身份凭证的请求 | true ; 若容许则请求与响应资源互通cookie |
Access-Control-Expose-Headers |
容许客户端读取的响应头部 | x-server-one,x-server-two |
Access-Control-Max-Age |
预检请求的结果缓存多少秒 | 3600 ; 缓存时间内不进行 options 请求 |
Access-Control-Allow-Methods |
预检请求:实际请求容许的 HTTP 方法 | |
Access-Control-Allow-Headers |
预检请求:实际请求容许的自定义头部 |
非预检请求都是简单请求。缓存
当请求知足下述任一条件时,将首先使用 OPTIONS
方法发起一个预检请求到服务器,以获知服务器是否容许该实际请求。安全
PUT
/ DELETE
/ CONNECT
/ OPTIONS
/ TRACE
/ PATCH
Accept
/ Accept-Language
/ Content-Language
/ Content-Type
/ DPR
/ Downlink
/ Save-Data
/ Viewport-Width
/ Width
application/x-www-form-urlencoded
/ multipart/form-data
/ text/plain
例1:domain1.com
上 request.js
请求 domain2.com
上的 1.php
服务器
// request.js const req = new XMLHttpRequest(); // 跨域:须要返回响应头 Access-Control-Allow-Origin: * req.open('POST', 'https://domain2.com/1.php', true); // 客户端自定义请求头:须要返回响应头 Access-Control-Expose-Headers: X-Client-One,X-Client-Two req.setRequestHeader('X-Client-One', 'pingpong1'); req.setRequestHeader('X-Client-Two', 'pingpong2'); // 须要附带身份凭证:须要返回响应头 Access-Control-Allow-Credentials: true req.withCredentials = true; req.onreadystatechange = () => { // 请求已完成,且响应已就绪 if (req.readyState === 4) { console.log(req.getResponseHeader('x-server-one')); console.log(req.getResponseHeader('x-server-two')); console.log(req.response); } }; req.send();
过程cookie
# 请求1头 Origin: https://domain1.com Access-Control-Request-Headers: x-client-one,x-client-two Access-Control-Request-Method: POST # 响应1头 Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: X-Client-One,X-Client-Two Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH,OPTIONS Access-Control-Allow-Origin: https://domain1.com Access-Control-Expose-Headers: x-server-one,x-server-two x-server-one: hello x-server-two: hihi # 请求2头 Origin: https://domain1.com X-Client-One: pingpong1 X-Client-Two: pingpong2 # 响应2头 Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: X-Client-One,X-Client-Two Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH,OPTIONS Access-Control-Allow-Origin: https://domain1.com Access-Control-Expose-Headers: x-server-one,x-server-two x-server-one: hello x-server-two: hihi
例1:domain1.com
请求 domain2.com
上的 demo.woff2
app
<!-- index.html --> <style> @font-face { font-family: 'Demo'; src: url(http://diary8.com/demo.woff2) format('woff2'); } </style> <i style="font-family: Demo;">hi</i>
处理
# 请求1头 Origin: https://domain1.com # 响应1头 Access-Control-Allow-Origin: https://domain1.com
被污染
的canvas尽管不经过 CORS 就能够在 <canvas>
中使用其余来源的图片,可是这会污染画布,而且再也不认为是安全的画布,这将可能在 <canvas>
检索数据过程当中引起异常
canvas 被污染
的状况下不能使用此方法
例1:domain1.com
上 new Image()
读取 domain2.com/demo.jpg
内容
const img = new Image(); img.crossOrigin = 'anonymous'; img.addEventListener('load', () => { // 1.绘制canvas,将图片覆盖在上面 const domCanvas = document.createElement('canvas'); const ctx = domCanvas.getContext('2d'); domCanvas.width = img.width; domCanvas.height = img.height; ctx.drawImage(img, 0, 0); // 2.读取canvas内容(此处受限) console.log(domCanvas.toDataURL()); }); img.src = 'https://domain2.com/demo.jpg';
处理
# 请求1头 Origin: https://domain1.com # 响应1头 Access-Control-Allow-Origin: https://domain1.com
<img src="https://domain2.com/demo.jpg" crossorigin="use-credentials">
const img = new Image(); img.crossOrigin = 'use-credentials'; img.addEventListener('load', () => { // 图片加载完成 }); img.src = 'https://domain2.com/demo.jpg';
方法1: 经过canvas画图读取
const img = new Image(); img.crossOrigin = 'anonymous'; img.addEventListener('load', () => { // 1.绘制canvas,将图片覆盖在上面 const domCanvas = document.createElement('canvas'); const ctx = domCanvas.getContext('2d'); domCanvas.width = img.width; domCanvas.height = img.height; ctx.drawImage(img, 0, 0); // 2.读取canvas内容(此处受限) console.log(domCanvas.toDataURL()); }); img.src = 'https://domain2.com/demo.jpg';
方法2:File读取input file内容
<input id="img" type="file"> <script> const domImg = document.getElementById('img'); domImg.addEventListener('change', () => { const reader = new FileReader(); reader.addEventListener('load', () => { console.log(reader.result); }); reader.readAsDataURL(domImg.files[0]); }); </script>