• XMLHttpRequest


    • 浏览器在XMLHttpRequest类上定义了他们的HTTP API
    • XMLHttpRequest类的每个实例表示了一个独立的请求/相应对
    • HTTP请求包括:HTTP请求方法(post还是get),请求URL,一个可选的请求头集合,一个可选的请求主体
    • HTTP响应包括:一个数字或者文字组策划过的状态吗(显示请求的成功失败),一个响应头集合,响应主体
    • 步骤:
    1. 实例化XMLHttpRequest对象 :
    var request=new XMLHttpRequest();

      2.指定请求

    request.open("method","url");

    第一个参数:指定HTTP方法或动作,“GET”适用于当URL完全猴子腚请求资源,当请求对服务器没有任何副作用以及当服务器的响应是可缓存的。

                     “POST"常用语form表单,请求主体中包含额外数据(表单数据)且这些数据常存储到服务器上的数据库中(副作用)

    第二个参数:url,如果使用绝对url,协议主机和端口常匹配所在文档的对象内容:跨域的请求常常会报错

      3.设置请求头

    request.setRequestHeader(“Content-Type”,"text/plain");

    对相同请求头调用多次setRequestHeader并不会覆盖,而是赋予多次的值。

       /*以post方式发送数据给服务器*/    
    function postMessage(msg){
            var request=new XMLHttpRequest();
            request.open("post","handlerPost");
            request.setRequestHeader('Content-Type','text/plain;charset=UTF-8');
            request.send(msg);
        }

    一个HTTP响应:状态吗,响应头集合,响应主体。

    XMLHttpRequest对象的属性和方法中可以获得以上值:

    1.status和statusText属性以数字和纯文本的格式赶回HTTP状态码。200:请求成功;404:URL不能匹配服务器上任何资源。

    2.getResponseHeader()和getResponseHeaders()查询响应头

    3.响应主体冲responseText属性中得到文本形式,从responseXML得到Document形式

    XMLHttpRequest对象通常异步使用:发送请求之后,send()方法立即返回,之后再返回响应。为了在响应准备就绪是得到通知,必须使用readystatechange事件。

    XMLHttpRequest的readyState属性指定了HTTP请求的状态,4:响应完成,3:接收到响应主体,2:接受到头信息。

        //postMessage("This is post message!");
        //发送一个HTTP    GET请求以获得指定URL内容
        //当响应成功到达,验证它是否是纯文本
        //如果是,把它传递给指定回调函数
        function getText(url,callback){
            var request=new XMLHttpRequest();
            request.open("GET",url);
            request.onreadystatechange=function(){
                //如果请求完成,则它是成功的
                if(request.readyState===4 && request.status===200){
                    var type=request.getResponseHeader("Content-Type");
                    if(type.match(/^text/))  //确保相应是文本
                        callback(request.responseText);
                }
            }
        }

    同步响应:

        //同步响应
        //发起同步的HTTP GET请求以获得指定URL的内容
        //返回响应文本,或如果请求不成功或响应不是文本就报错。
        function getTextSync(url){
            var request=new XMLHttpRequest();
            request.open("GET",url,false); //把fasle作为第三个参数传递给open(),那么send()方法将阻塞直到请求完成
            request.send(null);
    
            if(request.status!==200) throw new Error(request.statusText);
    
            var type=request.getResponseHeader('Content-Type');
            if(!type.match(/^text/)) throw new Error("Expected textual respomse;got:"+type);
    
            return request.responseText;
        }

    响应解码

     ///发送HTTP GET响应以获取指定URL内心哦那个
        //当响应到达时候,把它解析后的XML Document对象,解析后的JSON对象或字符串形式传递给回调
        function get(url,callback){
            var request=new XMLHttpRequest();
            request.open('GET',url);
            request.onreadystatechange=function(){
                if(request.readyState===4 && request.status===200){
                    var type=request.getResponseHeader("Content-Type");
                    if(type.indexOf("xml") !== -1 && request.responseXML){ 
                        callback(request.responseXML); //Document对象响应
                    }else if(type=== 'application/json'){
                        callback(JSON.parse(request.responseText)) //JSON响应
                    }else {
                        callback(request.responseText);
                    }
                }
            };
            request.send(null);
        }

    不用考虑特殊编码的另一个相应类型application/javascript亦或text/javascript,如果你想使用XMLHttpRequest请求Javascript脚本,然后使用eval()的话,因为<script>能发起跨域请求(JSONP就是运用了这一点),但是XMLHttpRequest API则禁止。

    web服务器也可使用二进制数据(例如,图片文件)相应HTTP请求。

        //使用XMLHttpRequest下载Blob
        //以Blob的形式获取URL指定的内容,并将其传递给指定的回调函数
        function getBlob(url,callback){
            var xhr=new XMLHttpRequest(); //创建一个新的XHR对象
            xhr.open("GET",url); //指定要获取内容的URL
            xhr.responseType="blob"; //以BLOB形式
            xhr.onload=function(){ //onload比onstatechange更容易
                callback(xhr.response); //注意,这里是response不是.responseText
            };
            xhr.send(null);
        }

    服务器响应的正常解码是建立在服务器端发送的"Content-type"和MIME类型上的。

    如果服务器端发送过的是XML文档,但是设置“Content-type”错误,将导致XMLHttpRequest对象将使用错误的编码来相应。

    所以overrideMimeType方法将重写服务端返回的MIME类型,注意该方法要在send()之前调用

        //无论服务器端设置的Content-type是什么类型,豆浆把它当作文本类型来处理
        request.overrideMimeType("text/plain;charset=utf-8");

    表单编码的请求

    //将对象{find:"pizza",zipcode:01234,radius:"1km"}变成表单编码的格式 find=pizza&zipcode=01234$radius=1km 的形式
        function encodeFormData(data){
            if(!data) return "";
            var pairs=[];
            for(var name in data){
                if(!data.hasOwnProperty(name)) continue; //跳过继承方法
                if(typeof  data[name] === "function") continue;//跳过方法
                var value=data[name].toString();
                name=encodeURIComponent(name.replace("%20","+"));
                value=encodeURIComponent(value.replace("%20","+"));
                pairs.push(name+"="+value);
            }
            return pairs.join('&');
        }

    HTTp POST请求包含一个请求主体,它包含客户端传递给服务端的数据。表单数据编码格式的正确MIME类型:

    当POST方法提交这种顺序的表单数据时,必须设置“Content-type”请求头为这个值。

    //使用表单数据发起一个HTTP POST请求
    function postData(url,data,callback){
            var request=new XMLHttpRequest();
            request.open("POST",url);
            request.onreadystatechange=function(){
                if(request.readyState===4 && callback)
                    callback(request);
            };
            request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
            request.send(encodeFormData(data)); //发送表单编码数据
        }

    HTTP GET请求没有请求主体:

     //使用表单编码数据发起get请求
        function getData(url,data,callback){
            var request=new XMLHttpRequest();
            request.open("GET",url+"?"+encodeFormData(data));
            request.onreadystatechange=function(){
                if(request.readyState===4 && callback) callback(request);
            };
            request.send(null);
        }

    JSON编码请求

        //使用JSON编码主题发起HTTP POST请求
        function postJSON(url,data,callback){
            var request=new XMLHttpRequest();
            request.open("POST",url);
            request.onreadystatechange=function(){
                if(request.readyState===4&&callback)
                    callback(request);
            };
            request.setRequestHeader("Content-Type","application/json"); 
            request.send(JSON.stringify(data));
        }

    HTTP进度事件

    在XHR2规范中,XMLHttpRequest对象在请求的不同阶段将触发不同类型的事件,所以不再需要检查readyState属性

    当调用send()事件时,触发单个loadstart事件,当正在加载服务器的相应时,XMLHttpRequest对象会发生progress事件,通常每隔50毫秒左右,所以可以使用这些事件给用户反馈请求进度。如果请求快速完成,它可能不会触发progress事件。当事件完成时,触发load事件。

    一个完成的请求不一定是成功的请求,例如:load事件的处理程序应该检车XMLHttpRequest对象的status状态来确定收到的是“200 OK”而不是“400 Not Found”的HTTP响应。

    HTTP请求无法完成有三种情况,对应三种事件

    1.请求超时:timeout时间

    2.请求中止:abort事件

    3.阻止请求完成:比如太多重定向这样的网络错误:error事件

    对于任何具体的请求,浏览器只会触发load,abort,timeout和error事件中的一个,一旦这些事件触发后,将触发loadend事件。需要在send()之前进行事件监听,下面是下载事件被触发:

    var req = new XMLHttpRequest();
    
    req.addEventListener("progress", updateProgress, false);
    req.addEventListener("load", transferComplete, false);
    req.addEventListener("error", transferFailed, false);
    req.addEventListener("abort", transferCanceled, false);
    
    req.open();
    
    ...
    
    // progress on transfers from the server to the client (downloads)
    function updateProgress(evt) {
      if (evt.lengthComputable) {
        var percentComplete = evt.loaded / evt.total;
        ...
      } else {
        // Unable to compute progress information since the total size is unknown
      }
    }
    
    function transferComplete(evt) {
      alert("The transfer is complete.");
    }
    
    function transferFailed(evt) {
      alert("An error occurred while transferring the file.");
    }
    
    function transferCanceled(evt) {
      alert("The transfer has been canceled by the user.");
    }

    下面是上传事件被触发:

    var req = new XMLHttpRequest();
    
    req.upload.addEventListener("progress", updateProgress);
    req.upload.addEventListener("load", transferComplete);
    req.upload.addEventListener("error", transferFailed);
    req.upload.addEventListener("abort", transferCanceled);
    
    req.open();

    判断是否支持progress事件

        if("onprogress" in (new XMLHttpRequest())){
            //支持progress事件
        }

    和progress事件相关联的事件对象上有三个有用的属性

    1.loaded属性是目前传输的字节数值

    2.total属性是自"Content-Length"头传输的数据的整体长度(单位字节)

    3.知道上面的长度则lengthComutable为true,反之亦然。

        request.onprogress=function(e){
            if(e.lengthComputable){
                progress.innerHTML=Math.round(100* e.loaded/ e.total)+"% Complete";
            }
        };

    中止请求和超时

        ///实现超时
        //如果响应成功到达,传入responseText给回调函数
        //如果响应在timeout毫秒内没有到达,中止这个请求
        //浏览器可能在abort()后出发“readystatechange”
        //如果是部分请求结果到达,设置可能设置status属性
        //所以需要设置一个标记,当部分且超时的响应到达时不会调用回调函数
        ///如果使用load事件就没有这个风险
        function timedGetText(url,timeout,callback){
            var request=new XMLHttpRequest();
            var timedout=false;
            //启动计时器,在timeout毫秒之后将终止请求
            var timer=setTimeout(function(){
                timedout=true;
                request.abort();
            },
            timeout);
            
            request.open("GET",url);
            request.onreadystatechange = function(){ //定义事件处理程序
                if(request.readyState !== 4) return; //忽略未完成的请求
                if(timedout) return;                 //忽略终止请求
                clearTimeout(timer);                //取消等待的超时
                if(request.status === 200)          //如果请求成功
                    callback(request.responseText); //把response传给回调
            };
            request.send(null);
        }

    跨域请求

    作为同源策略的一部分,XMLHttpRequest对象通常仅可以发起和文档具有相同服务器的HTTP请求,这个限制关闭了安全漏洞,但是同时也阻止了大量适合使用的跨域请求。

    CORS支持的跨域请求工作不需要做任何的事情,但是安全细节要了解

    1.给open()方法传递的用户名和密码将绝对不会通过跨域请求发送

    2.跨域请求不会包含其他的任何用户证书:cookie和HTTP身份验证令牌(token)通常不会作为请求内容发送

     1    /*
     2     *
     3     * linkdetails.js
     4     *
     5     * 这个常见的javascript模块查询有href属性但是没有title属性的所有<a>元素
     6     * 并给他们注册onmouseover事件处理程序
     7     * 这个时间处理程序使用XMLHttpRequest HEAD请求取得链接资源的详细信息
     8     * 然后把這写详细信息设置成链接的title属性
     9     * 这样他们会在工具提示中显示
    10     * */
    11 whenReady(function(){
    12     //是否有机会使用跨域请求?
    13     var supportsCORS= (new XMLHttpRequest()).withCredentials !== undefined;
    14 
    15     //遍历文档中的所有链接
    16     var links=document.getElementsByTagName('a');
    17     for(var i=0;i<links.length;i++){
    18         var link=links[i];
    19         if(!link.href) continue; //跳过没有超链接的锚点
    20         if(link.title) continue; //跳过已经有工具提示的链接
    21         //如果这是一个跨域链接
    22         if(link.host !== location.host || link.protocol !== location.protocol){
    23             link.title="站外链接"; //假设我们不能得到任何信息
    24             if(!supportsCORS) continue; //如果没有CORS支持就退出
    25            //否则,我们能了解这个链接的更多信息
    26             //所以继续前行,注册事件处理程序,于是我们可以尝试
    27         }
    28         //注册事件处理程序,当鼠标悬停时下载链接详细信息
    29         if(link.addEventListener)
    30             link.addEventListener("mouseover",mouseHandler,false);
    31         else
    32             link.attachEvent("onmouseover",mouseHandler);
    33     }
    34 
    35     function mouseHandler(e){
    36         var link = e.target || e.srcElement; //<a>元素
    37         var url=link.href;                  //链接url
    38 
    39         var req=new XMLHttpRequest();       //新请求
    40 
    41         req.open("HEAD",url);               //仅仅询问头信息
    42         req.onreadystatechange=function(){
    43             if(req.readyState !== 4) return; //忽略未完成的请求
    44             if(req.status === 200){  //如果成功
    45                 var type=req.getResponseHeader("Content-Type"); //获取链接的详细信息
    46                 var size=req.getResponseHeader("Content-Length");
    47                 var date=req.getResponseHeader("Last-Modified");
    48 
    49                 //在工具提示中显示详细信息
    50                 link.title="类型:"+type+"
    "+
    51                         "大小:"+size+"
    "+"时间:"+date;
    52             }else{
    53                 //如果请求失败,且链接没有“站外链接”的工具提示,那么显示这个错误
    54                 //if(!link.title)
    55                     link.title="不能获取详情:
    "+
    56                             req.status+" statusText"+req.statusText;
    57             }
    58         };
    59         req.send(null);
    60 
    61         //移除处理程序,仅想要一次获取这些头信息
    62         if(link.removeEventListener)
    63             link.removeEventListener("mouseover",mouseHandler,false);
    64         else
    65             link.detachEvent("onmouseover",mouseHandler);
    66     }
    67 });
    View Code

    出现的bug

    No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.


    XMLHttpRequest2 进行跨域访问时需要服务器许可,不是任何域都接受跨域请求的。先来看一下从 Yahoo YQL 域返回的响应头(Response Header ):注意:

    1 HTTP/1.1 200 OK
    2 Set-Cookie: AO="o=1&s=1&dnt=1"; Version=1; Domain=yahoo.com; Max-Age=630720000; Expires=Sat, 18-Jun-2033 10:07:41 GMT; Path=/
    3 Access-Control-Allow-Origin: *
    4 Cache-Control: public, max-age=899
    5 Content-Type: text/xml;charset=utf-8
    6 Content-Encoding: gzip
    7 Vary: Accept-Encoding
    8 Date: Sun, 23 Jun 2013 10:07:40 GMT

    注意里面有一条标识 Access-Control-Allow-Origin:* ,这就表示允许跨域访问,所以可以正常访问该域,而对于其他没有该标识的域就会出现禁止访问提示。

    解决方法:

    1.在服务器端设置response头,php是<?php header('Access-Control-Allow-Origin: *'); ?>,当然会让你的服务器网站变得很危险

    2.在chrom浏览器中设置

      1)安装Chrom插件(你得先翻了墙( ̄▽ ̄)"):点击这里

      2)在windows中window+r打开运行,输入

    chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security

    还要注意的一点是:chrome不支持本地运行Access-Control-Allow-Origin,所以为了可以让chrome浏览器在头部发送Access-Control-Allow-Origin,你必须结合你的hosts文件将localhost指定成其他域名:127.0.0.1 localhost yourdomain.com

    JSONP

    function foo(data)
    {
        // do stuff with JSON
    }
    
    var script = document.createElement('script');
    script.src = '//example.com/path/to/jsonp?callback=foo'
    
    document.getElementsByTagName('head')[0].appendChild(script);
  • 相关阅读:
    [BUUCTF 2018]Online Tool
    [ZJCTF 2019]NiZhuanSiWei 1
    [极客大挑战 2019]PHP
    [De1CTF 2019]SSRF Me
    2018网鼎杯 Fakebook
    [CISCN2019 华北赛区 Day2 Web1]Hack World
    SUCTF checkin
    强网杯 高明的黑客
    GYCTF Ezsqli
    GYCTF 盲注【regexp注入+时间盲注】
  • 原文地址:https://www.cnblogs.com/RachelChen/p/5431704.html
Copyright © 2020-2023  润新知