前端脚本化http

超文本传输协议(http)规定web浏览器如何从web服务器获取文档和向web服务器提交表单内容,以及web服务器如何响应这些请求和提交。通常http并不在脚本的控制下,只是当用户单击链接,提交表单和输入URL时才发生
但是用js来操纵http是可行的,当脚本设置window对象的location属性(当然改变location的hash锚点不算)或调用表单对象的submit方法时,都会初始化http请求。
ajax的主要特点是使用脚本操纵http和web服务器进行交互,不会导致页面重载
而在comet中,web服务器发起通信并发送消息到客户端,也就是服务器向客户端推数据

ajax

ajax的核心是XMLHttpRequest,也就是我们常说的xhr对象。一个http请求包括4部分:请求方法或动作,正在请求的URL,一个可选的请求头信息(可能包括身份验证的cookie等),一个可选的请求主体。而服务器返回的http响应包括3部分:一个数字和文字组成的状态码(用来显示请求的成功或失败),一个响应头集合,响应主题。浏览器需要考虑cookie,重定向,缓存和代理,但代码只需要关心请求和响应。
在创建了xhr对象之后,发起http请求的下一步是调用xhr对象的open()方法取指定这个请求的两个必需部分:方法和URL。open的第三个参数代表同步或者异步,如果是同步的话,多传一个false参数

    //request这里代表xhr对象
    request.open('GET', '/xxx/xxx');

如果有请求头的话,下一步就是设置它,比如POST请求需要设定MIME类型

   request.setRequestHeader('Content-Type', 'text/plain');

如果对相同的头调用setRequestHeader()多次,新值不会取代之前指定的值。你不能通过这个方法自己指定'Content-Length', 'Date''Referer''User-Agent'cookie这些头部,因为浏览器会根据xhr对象自动添加,防止你伪造他们。
使用xhr发起http请求的最后一步是指定可选的请求主体并向服务器发送它。使用send() 方法

   //send中包含主体,如果是GET请求没有主体就传null
   request.send(null);

一个发送纯文本请求的ajaxPOST请求

   function postMessage(){
      //新请求,这里省略兼容性写法
      var request = new XMLHttpRequest();
      request.open('POST', '/xx/xx');
      //请求主体将是纯文本
      request.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
      request.send(msg);
   }

发送请求之后,send()方法立即返回。为了响应准备就绪时得到通知,必须监听xhr对象上的readystatechange事件。readyState是一个整数,它的值为0代表open()尚未调用,值为1代表open()已经调用但尚未调用send方法,值为2代表send方法已经调用,值为3代表接收到部分数据,值为4代表响应完成。每次readyState属性改变都会出发readystatechange事件。

   request.onreadystatechange = function(){
      //request.status代表响应的http状态
      //request.statusText是http状态的说明
      if(request.readyState === 4 && request.status === 200){
         var type = request.getResponseHeader('Content-Type');
         //确保响应是文本
         if(type.match(/^text/)){
             callback(request.responseText);
         }
         //如果是json数据
         if(type === 'application/json'){
             callback(JSON.parse(request.responseText))
         }
      }
   }

编码请求主体

http POST请求包括一个请求主体,它包含客户端传递给服务器的数据。
当用户提交表单时,表单中的数据(key和value)编码到一个字符串中并随请求发送。一个简单表单的编码像如下这样

   name=sysuzhyupeng&age=24&birthday=19930227

表单的表码格式有一个正式的MIME类型

   application/x-www-form-urlencoded

当使用POST方法提交这种顺序的表单数据时,必须设置Content-Type请求头为这个值。(如果直接在HTML里面提交而不是使用ajax,浏览器会自动把表单的数据编码并设置头部)。服务器得到的数据变成js对象的格式可能是

   {
      name: 'sysuzhyupeng',
      age: '24',
      birthday: '19930227'
   }

如果使用GET请求,则在open的请求上加上查询字符串

   request.open('GET', url + '?' + encodeFormData(data));
   request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

除了表单编码我们可以使用json编码

   request.setRequestHeader('Content-Type', 'application/json');
   request.send(JSON.stringify(data));

也可以是xml编码的请求,这里就不再叙述。
HTML表达的特性之一是当用户通过< input type=”file” />元素选择文件的时候,表单将在它产生的POST请求主体上发送文件内容了。而在xhr对象中

   if(input.type == 'file'){
      input.addEventListener('change', function(){
         //每个<input type="file" />元素都有一个files属性
         //假设只选择单个文件
         var file = this.files[0];
         if(!file) return;
         var request = new XMLHttpRequest();
         request.open('POST', url);
         //文件类型是更通用的二进制大对象(Blob)类型中的一个子类型,因此直接扔进去就行
         request.send(file);
      }, false);
   }

当HTML表单同时包含文件上传元素和其他元素时,浏览器不能使用普通的表单编码而必须使用'multipart/form-data' 的特殊Content-Type来用POST方法提交表单。xhr2定义了新的FormData API,使用下列代码我们不用设置Content-Type

   var formdata = new FormData();
   //假设data中包含文件和其他元素
   for(name in data){
      //跳过继承的属性
      if(!data.hasOwnProperty(name)) continue;
      var value = data[name];
      //跳过方法
      if(typeof value === 'function') continue;
      //这里允许file对象
      formdata.append(name, value);
   }
   //当传入formdata对象时,send()会自动设置Content-Type头
   request.send(formdata);

中止请求和超时

可以使用xhr对象的abort 方法来取消正在进行的http请求,调用abort的主要原因是完成取消或超时请求消耗的时间太长。

   var request = new XMLHttpRequest();
   var timeout = false;
   var timer = setTimeout(function(){
      timeout = true;
      request.abort();
   }, 1000);
   request.onreadystatechange = function(){
      if(request.readState !== 4) return;
      if(timeout) return;
      clearTimeout(timer);
      //请求成功
      if(request.status === 200){
          callback(request.responseText);
      }
   }

JSONP跨域

使用JSONP进行ajax传输的一个主要原因是,它不受同源策略的影响,因此可以使用他们从其他源的服务器请求数据,第二个原因是包含JSON编码数据的响应体会自动解码。
我们源页面是在a.com,想要获取b.com的数据,我们可以动态插入来源于b.com的脚本:

        function jsonpServer(url) {
            var script = document.createElement("script");
            script.setAttribute("type", "text/javascript");
            script.setAttribute("src", url);
            document.body.appendChild(script);
        }   
        function JSON_CALLBACK(data) {
            console.log(data);
        }

b.com页面接受到这个请求时,如果没有标识为JSONP, 会正常返回json的数据结果,像这样:

   [{"id":"1","name":"syzuzhyupeng"},{"id":"2","name":"zhyupeng"}]

而利用JSONP,服务端会接受这个callback参数(不然请求的页面无法进行下一步操作),然后用这个参数值包装要返回的数据:

   <?php
    $data = '[{"id":"1","name":"syzuzhyupeng"},{"id":"2","name":"zhyupeng"}]';
    $data = "JSON_CALLBACK(" . $data . ")";
    echo $data;
    ?>

包裹后的响应会成为< script>元素的内容。
那么我们怎么告知服务器使用JSONP的响应而不是普通的JSON响应呢,这个可以通过在URL中添加一个查询参数来实现,例如追加'?json''&json'
虽然JSONP在跨域ajax请求方面有很强的能力,但是它也有一些缺陷。首先,它没有关于JSONP调用的错误处理,一旦回调函数调用失败,浏览器没有反应。

domain

二级域名的情况下,domain属性可以设置为对应的一级域名。比如,当前域名是sub.example.com,则domain属性可以设置为example.com。除此之外的写入,都是不可以的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值