XMLHTTPRequest
浏览器与服务器之间采用http协议进行通信,通过在地址栏输入网址向服务器发送请求,AJAX指的是通过JavaScript异步通信从而从服务器中获取xml文档中提取数据,在更新网页相应部分,而不用刷新整个页面。
具体来说AJAX具体分为几个步骤:
创建XMLHTTPRequest实例
发出HTTP请求
接受服务器传回的数据
更新网页相应位置的数据
换句话来说,就是AJAX通过原来的XMLHTTPRequest对象发送http请求,得到服务器传回的数据再进行处理,使浏览器页面的相应部分进行刷新,而不是刷新整个页面,但是呢AJAX已经不是字面上的意思了,也就是说服务器传回的数据已经是JSON格式的,而不是XML文本格式的了
XMLHTTPRequest对象是AJAX的主要接口,用于浏览器与服务器之间的通信,尽管字面意思上有XML和HTTP,实际上可以可以使用不同的协议,以及传回数据的文本格式也有所改变
实例
XMLHTTPRequest原本是一个构造函数,可以通过new来创建新的实例
var xhr = new XMLHttpRequest();
一旦建立好了新的实例就要通过open建立相应的连接,以及相关的细节问题
xhr.open('GET', 'http://www.example.com/page.php', true);
get为请求,与指定的服务器网址连接进行连接,后边的http://www.example.com/page.php就是指定的服务器网址,最后的参数true指相应的请求为异步
异步请求和同步请求相对,异步不需要等待响应,随时可以发送下一次请求。
如果是同步请求,需要将信息填写完整,再发送请求,服务器响应填写是否正确,再做修改。
但是异步请求是局部页面更新。
然后回调函数进行监听,监听相应通信的状态变化
xhr.onreadystatechange = handleStateChange;
function handleStateChange() {
// ...
}
相应函数一旦发生变化,就会调用进行监听函数handlestatechange
最后使用send函数进行发送请求
xhr.send(null);
上述代码的参数为null指的是发送请求不携带数据,如果发送post请求,此处就应该携带相应数据,一旦拿到服务器的数据,只更新相应位置,而不是更新整个页面
下面是XMLHTTPRequest对象的简单用法的完整例子
var xhr = new XMLHttpRequest(); //使用new建立新的实例
xhr.onreadystatechange = function(){ //回调函数进行监听,一旦发生变化,监听函数也会变化
// 通信成功时,状态值为4
if (xhr.readyState === 4){
if (xhr.status === 200){
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
}
};
xhr.onerror = function (e) {
console.error(xhr.statusText);
};
xhr.open('GET', '/endpoint', true); //用get进行连接,请求采用的是异步请求
xhr.send(null); //最后进行send函数发送请求,使相应位置进行变化,而不是刷新整个页面,null请求不携带数据体,使用post请求需要携带相应数据体,则就需要添加相应的参数
XMLHTTPRequest实例的属性
上述XMLHTTPRequrst的实例完整操作中遇到了几个并没有提出的函数,下面会讲述实例的相关属性
XMLHttpRequest.readyState
观察完整实例,会发现XMLHttpRequest.readyState返回一个整数,表示实例对象的当前状态。该属性只读。它可能返回以下值。
0,表示 XMLHttpRequest 实例已经生成,但是实例的open()方法还没有被调用。
1,表示open()方法已经调用,但是实例的send()方法还没有调用,仍然可以使用实例的setRequestHeader()方法,设定 HTTP 请求的头信息。
2,表示实例的send()方法已经调用,并且服务器返回的头信息和状态码已经收到。
3,表示正在接收服务器传来的数据体(body 部分)。这时,如果实例的responseType属性等于text或者空字符串,responseText属性就会包含已经收到的部分信息。
4,表示服务器返回的数据已经完全接收,或者本次接收已经失败。
通信过程中,每当实例对象发生状态变化,它的readyState属性的值就会改变。这个值每一次变化,都会触发readyStateChange事件。
var xhr = new XMLHttpRequest();
if (xhr.readyState === 4) {
// 请求结束,处理服务器返回的数据,表示服务器返回的数据已经完全接受或者接收失败
} else {
// 显示提示“加载中……”这里表示http请求还在进行中
}
XMLHttpRequest.onreadystatechange
这个属于一个监听函数,就是通过监听到通信状态的变化,监听函数也发生相应的变化,readystate发生变化就会触发这个属性,另外,如果使用实例的abort()方法,终止 XMLHttpRequest 请求,也会造成readyState属性变化,导致调用XMLHttpRequest.onreadystatechange属性。
var xhr = new XMLHttpRequest(); //使用new创建新的实例
xhr.open( 'GET', 'http://example.com' , true ); //建立相应连接,采用异步请求
xhr.onreadystatechange = function () { //监听,通过readystate返回相应的值判断通信状态
if (xhr.readyState !== 4 || xhr.status !== 200) {
return;
}
console.log(xhr.responseText);
};
xhr.send(); //通过send函数发送请求
XMLHttpRequest.response
此属性表示服务器返回的数据体,可以是任何类型,比如字符串、二进制对象等等,具体类型由responseType属性来决定,该属性也为只读
如果本次请求没有成功或者数据不完整,该属性等于null。但是,如果responseType属性等于text或空字符串,在请求没有结束之前(readyState等于3的阶段),response属性包含服务器已经返回的部分数据。
var xhr = new XMLHttpRequest(); //使用new创建实例
xhr.onreadystatechange = function () { //监听,如果实例对象状态返回值为4,返回相应的数据体
if (xhr.readyState === 4) {
handler(xhr.response);
}
}
XMLHttpRequest.responseType
服务器返回数据体的属性类型就是通过这个属性来决定的,这个属性是可写的,可以在调用open()方法之后、调用send()方法之前,设置这个属性的值,告诉浏览器如何解读返回的数据。如果responseType设为空字符串,就等同于默认值text。
""(空字符串):等同于text,表示服务器返回文本数据。
"arraybuffer":ArrayBuffer 对象,表示服务器返回二进制数组。
"blob":Blob 对象,表示服务器返回二进制对象。
"document":Document 对象,表示服务器返回一个文档对象。
"json":JSON 对象。
"text":字符串。
text类型适合大多数情况,而且直接处理文本也比较方便。document类型适合返回 HTML / XML 文档的情况,这意味着,对于那些打开 CORS(跨域) 的网站,可以直接用 Ajax 抓取网页,然后不用解析 HTML 字符串,直接对抓取回来的数据进行 DOM 操作。blob类型适合读取二进制数据,比如图片文件为二进制数据
var xhr = new XMLHttpRequest(); //创建实例
xhr.open('GET', '/path/to/image.png', true); //建立连接异步请求
xhr.responseType = 'blob'; //返回数据类型设置为blob类型适合读取二进制数据
xhr.onload = function(e) {
if (this.status === 200) {
var blob = new Blob([xhr.response], {type: 'image/png'});
// 或者
var blob = xhr.response;
}
};
xhr.send(); //发送请求
设置数据类型是为了使返回的数据得到相应的格式然后再进行处理
XMLHttpRequest.responseText
XMLHttpRequest.responseText属性返回从服务器接收到的字符串,该属性为只读。只有 HTTP 请求完成接收以后,该属性才会包含完整的数据。
var xhr = new XMLHttpRequest(); // 创建实例
xhr.open('GET', '/server', true); //建立连接,异步请求
xhr.responseType = 'text'; //返回的数据类型设置为text
xhr.onload = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send(null); //发送请求
XMLHttpRequest.responseXML
XMLHttpRequest.responseXML属性返回从服务器接收到的 HTML 或 XML 文档对象,该属性为只读。如果本次请求没有成功,或者收到的数据不能被解析为 XML 或 HTML,该属性等于null。
该属性生效的前提是 HTTP 回应的Content-Type头信息等于text/xml或application/xml。这要求在发送请求前,XMLHttpRequest.responseType属性要设为document。如果 HTTP 回应的Content-Type头信息不等于text/xml和application/xml,但是想从responseXML拿到数据(即把数据按照 DOM 格式解析),那么需要手动调用XMLHttpRequest.overrideMimeType()方法,强制进行 XML 解析。
var xhr = new XMLHttpRequest(); //创建实例
xhr.open('GET', '/server', true); //建立连接异步请求
xhr.responseType = 'document'; //设置返回数据类型
xhr.overrideMimeType('text/xml'); //HTTP 回应的Content-Type头信息等于text/xml
xhr.onload = function () { //触发监听函数
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseXML);
}
};
xhr.send(null); //发送请求
XMLHttpRequest.responseURL
XMLHttpRequest.responseURL属性是字符串,表示发送数据的服务器的网址。
var xhr = new XMLHttpRequest(); //创建实例
xhr.open('GET', 'http://example.com/test', true);//建立连接异步请求
xhr.onload = function () {
// 返回 http://example.com/test
console.log(xhr.responseURL);
};
xhr.send(null); //发送请求
注意,这个属性的值与open()方法指定的请求网址不一定相同。如果服务器端发生跳转,这个属性返回最后实际返回数据的网址。另外,如果原始 URL 包括锚点(fragment),该属性会把锚点剥离。
XMLHttpRequest.status
XMLHttpRequest.statusText
XMLHttpRequest.status属性返回一个整数,表示服务器回应的 HTTP 状态码。一般来说,如果通信成功的话,这个状态码是200;如果服务器没有返回状态码,那么这个属性默认是200。请求发出之前,该属性为0。该属性只读。
200, OK,访问正常
301, Moved Permanently,永久移动
302, Moved temporarily,暂时移动
304, Not Modified,未修改
307, Temporary Redirect,暂时重定向
401, Unauthorized,未授权
403, Forbidden,禁止访问
404, Not Found,未发现指定网址
500, Internal Server Error,服务器发生错误
基本上,只有2xx和304的状态码,表示服务器返回是正常状态。
if (xhr.readyState === 4) {
if ( (xhr.status >= 200 && xhr.status < 300)
|| (xhr.status === 304) ) { // 处理服务器的返回数据
} else { // 出错
}
}
XMLHttpRequest.statusText属性返回一个字符串,表示服务器发送的状态提示。
不同于status属性,该属性包含整个状态信息,比如“OK”和“Not Found”。
在请求发送之前(即调用open()方法之前),该属性的值是空字符串;如果服务器没有返回状态提示,该属性的值默认为“OK”。该属性为只读属性。
XMLHttpRequest.timeout
XMLHttpRequestEventTarget.ontimeout
XMLHttpRequest.timeout属性返回一个整数,表示多少毫秒后,如果请求仍然没有得到结果,就会自动终止。如果该属性等于0,就表示没有时间限制。
XMLHttpRequestEventTarget.ontimeout属性用于设置一个监听函数,如果发生 timeout 事件,就会执行这个监听函数。
var xhr = new XMLHttpRequest(); //创建实例
var url = '/server';
xhr.ontimeout = function () { //设置时间限制,在多久没有得到结果就自动终止
console.error('The request for ' + url + ' timed out.');
};
xhr.onload = function() { //设置返回数据
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 处理服务器返回的数据
} else {
console.error(xhr.statusText);
}
}
};
xhr.open('GET', url, true); //创建连接异步请求
// 指定 10 秒钟超时
xhr.timeout = 10 * 1000; //设置超时时间
xhr.send(null); //发送请求
事件监听属性
XMLHttpRequest 对象可以对以下事件指定监听函数。
XMLHttpRequest.onloadstart:loadstart 事件(HTTP 请求发出)的监听函数
XMLHttpRequest.onprogress:progress事件(正在发送和加载数据)的监听函数
XMLHttpRequest.onabort:abort 事件(请求中止,比如用户调用了abort()方法)的监听函数
XMLHttpRequest.onerror:error 事件(请求失败)的监听函数
XMLHttpRequest.onload:load 事件(请求成功完成)的监听函数
XMLHttpRequest.ontimeout:timeout 事件(用户指定的时限超过了,请求还未完成)的监听函数
XMLHttpRequest.onloadend:loadend 事件(请求完成,不管成功或失败)的监听函数
progress事件的监听函数有一个事件对象参数,该对象有三个属性:loaded属性返回已经传输的数据量,total属性返回总的数据量,lengthComputable属性返回一个布尔值,表示加载的进度是否可以计算。所有这些监听函数里面,只有progress事件的监听函数有参数,其他函数都没有参数。
注意,如果发生网络错误(比如服务器无法连通),onerror事件无法获取报错信息。也就是说,可能没有错误对象,所以这样只能显示报错的提示。
XMLHttpRequest.withCredentials
XMLHttpRequest.withCredentials属性是一个布尔值,表示跨域请求时,用户信息(比如 Cookie 和认证的 HTTP 头信息)是否会包含在请求之中,默认为false,发送跨域请求时不会发送本机设置的cookie
如果需要跨域 AJAX 请求发送 Cookie,需要withCredentials属性设为true。注意,同源的请求不需要设置这个属性。
为了让这个属性生效,服务器必须显式返回Access-Control-Allow-Credentials这个头信息。
Access-Control-Allow-Credentials: true
withCredentials属性打开的话,跨域请求不仅会发送 Cookie,还会设置远程主机指定的 Cookie。
withCredentials属性没有打开,那跨域的 AJAX 请求即使明确要求浏览器设置 Cookie,浏览器也会忽略
注意,脚本总是遵守同源政策,无法从document.cookie或者 HTTP 回应的头信息之中,读取跨域的 Cookie,withCredentials属性不影响这一点。
XMLHttpRequest.upload
XMLHttpRequest 不仅可以发送请求,还可以发送文件,这就是 AJAX 文件上传。发送文件以后,通过XMLHttpRequest.upload属性可以得到一个对象,通过观察这个对象,可以得知上传的进展。主要方法就是监听这个对象的各种事件:loadstart、loadend、load、abort、error、progress、timeout。
通过这个对象来研究关于他相关的所有时间,监听这个对象的所有事件
XMLHttpRequest 的实例方法
XMLHttpRequest.open()
关于open的参数有5种
method:表示 HTTP 动词方法,比如GET、POST、PUT、DELETE、HEAD等。
url: 表示请求发送目标 URL。
async: 布尔值,表示请求是否为异步,默认为true。如果设为false
则send()方法只有等到收到服务器返回了结果,才会进行下一步操作。该参数可选。由于同步 AJAX 请求会造成浏览器失去响应,许多浏览器已经禁止在主线程使用,只允许 Worker 里面使用。所以,这个参数轻易不应该设为false。
user:表示用于认证的用户名,默认为空字符串。该参数可选。
password:表示用于认证的密码,默认为空字符串。该参数可选。
注意,如果对使用过open()方法的 AJAX 请求,再次使用这个方法,等同于调用abort(),即终止请求。
XMLHttpRequest.send()
XMLHttpRequest.send()方法用于实际发出 HTTP 请求。它的参数是可选的,如果不带参数,就表示 HTTP 请求只有一个 URL,没有数据体,典型例子就是 GET 请求;如果带有参数,就表示除了头信息,还带有包含具体数据的信息体,典型例子就是 POST 请求。
GET
var xhr = new XMLHttpRequest();
xhr.open('GET',
'http://www.example.com/?id=' + encodeURIComponent(id),
true
);
xhr.send(null);
GET请求的参数,作为查询字符串附加在 URL 后面
POST
var xhr = new XMLHttpRequest();
var data = 'email='
+ encodeURIComponent(email)
+ '&password='
+ encodeURIComponent(password);
xhr.open('POST', 'http://www.example.com', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(data);
所有的监听事件都要在send前完成
send方法的参数就是发送的数据。多种格式的数据,都可以作为它的参数。
可以在data前面加上相应的发送数据类型
如果send()发送 DOM 对象,在发送之前,数据会先被串行化。如果发送二进制数据,最好是发送ArrayBufferView或Blob对象,这使得通过 Ajax 上传文件成为可能。
FormData对象
构造表单数据
加工表单数据
XMLHttpRequest.setRequestHeader()
XMLHttpRequest.setRequestHeader()方法用于设置浏览器发送的 HTTP 请求的头信息。该方法必须在open()之后、send()之前调用。如果该方法多次调用,设定同一个字段,则每一次调用的值会被合并成一个单一的值发送。
该方法接受两个参数。第一个参数是字符串,表示头信息的字段名,第二个参数是字段值。
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Content-Length', JSON.stringify(data).length);
xhr.send(JSON.stringify(data));
设置头信息的类型以及数据长度
XMLHttpRequest.overrideMimeType()
XMLHttpRequest.overrideMimeType()方法用来指定 MIME 类型,覆盖服务器返回的真正的 MIME 类型,从而让浏览器进行不一样的处理。举例来说,服务器返回的数据类型是text/xml,由于种种原因浏览器解析不成功报错,这时就拿不到数据了。为了拿到原始数据,我们可以把 MIME 类型改成text/plain,这样浏览器就不会去自动解析,从而我们就可以拿到原始文本了。
注意,该方法必须在send()方法之前调用。
修改服务器返回的数据类型,不是正常情况下应该采取的方法。如果希望服务器返回指定的数据类型,可以用responseType属性告诉服务器,只有在服务器无法返回某种数据类型时,才使用overrideMimeType()方法。
var xhr = new XMLHttpRequest();
xhr.onload = function(e) {
var arraybuffer = xhr.response;
// ...
}
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.send();
在这种情况下才可以采用这种办法来告诉服务器数据类型,尽可能使用responsetype来告诉服务器数据类型
XMLHttpRequest.getResponseHeader()
XMLHttpRequest.getResponseHeader()方法返回 HTTP 头信息指定字段的值,如果还没有收到服务器回应或者指定字段不存在,返回null。该方法的参数不区分大小写。如果有多个字段同名,它们的值会被连接为一个字符串,每个字段之间使用“逗号+空格”分隔。
function getHeaderTime() {
console.log(this.getResponseHeader("Last-Modified"));
}
var xhr = new XMLHttpRequest();
xhr.open('HEAD', 'yourpage.html');
xhr.onload = getHeaderTime;
xhr.send();
XMLHttpRequest.abort()
XMLHttpRequest.abort()方法用来终止已经发出的 HTTP 请求。调用这个方法以后,readyState属性变为4,status属性变为0。
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.example.com/page.php', true);
setTimeout(function () {
if (xhr) {
xhr.abort();
xhr = null;
}
}, 5000);
发出请求5秒后,终止请求
XMLHttpRequest 实例的事件
readyStateChange 事件
readyState属性的值发生改变,就会触发 readyStateChange 事件。
我们可以通过onReadyStateChange属性,指定这个事件的监听函数,对不同状态进行不同处理。尤其是当状态变为4的时候,表示通信成功,这时回调函数就可以处理服务器传送回来的数据。
progress 事件
上传文件时,XMLHttpRequest 实例对象本身和实例的upload属性,都有一个progress事件,会不断返回上传的进度。
load 事件、error 事件、abort 事件
load 事件表示服务器传来的数据接收完毕,error 事件表示请求出错,abort 事件表示请求被中断(比如用户取消请求)。
loadend 事件
abort、load和error这三个事件,会伴随一个loadend事件,表示请求结束,但不知道其是否成功。
timeout 事件
服务器超过指定时间还没有返回结果,就会触发 timeout 事件,具体的例子参见timeout属性一节。
Referer
Referer是 HTTP请求header 的一部分,当浏览器(或者模拟浏览器行为)向web 服务器发送请求的时候,头信息里有包含 referer。比如我在http://www.google.com 里有一个http://www.google.com 链接,那么点击这个http://www.google.com ,它的header 信息里就有:
Referer=http://www.google.com
服务端一般使用Referer(注:正确英语拼写应该是referrer,由于早期HTTP规范的拼写错误,为了保持向后兼容就一直延续下来)请求头识别访问来源,可能会以此统计分析、日志记录以及缓存优化等。
防盗链
Referer=http://www.google.com
可以通过这个进行防盗链,比如我只允许我自己网站访问自己的服务器,那么每次访问前会通过referer进行对比是不是自己的网址,如果是就可以访问,如果不是就进行拦截
将这个http请求发给服务器后,如果服务器要求必须是某个地址或者某几个地址才能访问,而你发送的referer不符合他的要求,就会拦截或者跳转到他要求的地址,然后再通过这个地址进行访问
盗链是指在自己的页面上展示一些并不在自己服务器上的一些内容, 获取别人的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容。 一般被盗链的都是图片、 可执行文件、 音视频文件、压缩文件等资源。通过盗链的手段可以减轻自己服务器的负担
防止恶意请求
比如静态请求是*.html结尾的,动态请求是*.shtml,那么由此可以这么用,所有的*.shtml请求,必须 Referer 为我自己的网站。
空Referer是怎么回事?什么情况下会出现Referer?
首先,我们对空 Referer 的定义为, Referer 头部的内容为空,或者,一个 HTTP 请求中根本不包含 Referer头部。
那么什么时候 HTTP 请求会不包含 Referer 字段呢?根据Referer的定义,它的作用是指示一个请求是从哪里链接过来,那么当一个请求并不是由链接触发产生的,那么自然也就不需要指定这个请求的链接来源。
比如,直接在浏览器的地址栏中输入一个资源的URL地址,那么这种请求是不会包含 Referer 字段的,因为这是一个“凭空产生”的 HTTP 请求,并不是从一个地方链接过去的。
那么在防盗链设置中,允许空Referer和不允许空Referer有什么区别?
允许 Referer 为空,意味着你允许比如浏览器直接访问,就是空。
绕过防盗链
那么现在的很多网站是如何利用referer来进行防图片盗链的呢?三种情况下允许引用图片:
本网站。
无referer信息的情况。(服务器认为是从浏览器直接访问的图片URL,所以这种情况下能正常访问)
授权的网址。
设置meta以及referrerpolicy
Referrer-policy
Referrer-policy作用就是为了控制请求头中referer的内容
包含以下值:
no-referrer : 整个referee首部会被移除,访问来源信息不随着请求一起发送。
no-referrer-when-downgrade : 在没有指定任何策略的情况下用户代理的默认行为。在同等安全级别的情况下,引用页面的地址会被发送(HTTPS->HTTPS),但是在降级的情况下不会被发送 (HTTPS->HTTP).
origin: 在任何情况下,仅发送文件的源作为引用地址。例如 https://example.com/page.html 会将 https://example.com/ 作为引用地址。
origin-when-cross-origin: 对于同源的请求,会发送完整的URL作为引用地址,但是对于非同源请求仅发送文件的源。
same-origin: 对于同源的请求会发送引用地址,但是对于非同源请求则不发送引用地址信息。
strict-origin: 在同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS),但是在降级的情况下不会发送 (HTTPS->HTTP)。
strict-origin-when-cross-origin: 对于同源的请求,会发送完整的URL作为引用地址;在同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS);在降级的情况下不发送此首部 (HTTPS->HTTP)。
unsafe-url: 无论是同源请求还是非同源请求,都发送完整的 URL(移除参数信息之后)作为引用地址。(最不安全了)
设置referer
在HTML里设置meta
<meta name="referrer" content="origin">
或者用<a>、<area>、<img>、<iframe>、<script> 或者 <link> 元素上的 referrerpolicy 属性为其设置独立的请求策略。
<script src='/javascripts/test.js' referrerpolicy="no-referrer"></script>
利用iframe伪造请求referer
const putNoRefererImage = (() => {
let iframe
/*
src: 图片地址
wrap:需要加载图片的容器
*/
return function (src, wrap) {
if (iframe) {
iframe.remove()
}
let url = new URL(src);
let frameid = 'frameimg' + Math.random();
window.img = `<img id="tmpImg" width=400 src="${url}" alt="图片加载失败,请稍后再试"/> `;
// 构造一个iframe
iframe = document.createElement('iframe')
iframe.id = frameid
iframe.src = "javascript:parent.img;" // 通过内联的javascript,设置iframe的src
// 校正iframe的尺寸,完整展示图片
iframe.onload = function () {
var img = iframe.contentDocument.getElementById("tmpImg")
if (img) {
iframe.height = img.height + 'px'
iframe.width = img.width + 'px'
}
}
iframe.width = 200
iframe.height = 200
iframe.scrolling = "no"
iframe.frameBorder = "0"
wrap.appendChild(iframe)
}
})();
putNoRefererImage(imgSrc, document.body);
客户端在请求时修改header头部
XMLHTTPRequest
XMLHttpRequest中setRequestHeader方法,用于向请求头添加或修改字段
// 通过ajax下载图片
function loadImage(uri) {
return new Promise(resolve => {
let xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.onload = function() {
resolve(xhr.response);
};
xhr.open("GET", uri, true);
// 通过setRequestHeader设置header不会生效
// 会提示 Refused to set unsafe header "Referer"
xhr.setRequestHeader("Referer", "");
xhr.send();
});
}
// 将下载下来的二进制大对象数据转换成base64,然后展示在页面上
function handleBlob(blob) {
let reader = new FileReader();
reader.onload = function(evt) {
let img = document.createElement('img');
img.src = evt.target.result;
document.getElementById('container').appendChild(img)
};
reader.readAsDataURL(blob);
}
const imgSrc = "https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg";
loadImage(imgSrc).then(blob => {
handleBlob(blob);
});
上述代码运行时会发现控制台提示错误:
Refused to set unsafe header "Referer"
可以看见setRequestHeader设置referer响应头是无效的,这是由于浏览器为了安全起见,无法手动设置部分保留字段,不幸的是Referer恰好就是保留字段之一
fetch
// 将下载下来的二进制大对象数据转换成base64,然后展示在页面上
function handleBlob(blob) {
let reader = new FileReader();
reader.onload = function(evt) {
let img = document.createElement('img');
img.src = evt.target.result;
document.getElementById('container').appendChild(img)
};
reader.readAsDataURL(blob);
}
const imgSrc = "https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg";
function fetchImage(url) {
return fetch(url, {
headers: {
// "Referer": "", // 这里设置无效
},
method: "GET",
referrer: "", // 将referer置空
// referrerPolicy: 'no-referrer',
}).then(response => response.blob());
}
fetchImage(imgSrc).then(blob => {
handleBlob(blob);
});
通过将配置参数referrer置空,可以看见本次请求已经不带referer了,或者设置 referrerPolicy为"no-referrer"

1444

被折叠的 条评论
为什么被折叠?



