AJAX jsonp实现过程

原生JavaScript实现AJAX、JSONP
l跨域的问题
?域:域名
?跨域请求(访问):一个域名下的文件请求另外一个域名下的资源,就产生了跨域
l跨域的解决
?Jsonp : json padding
l<script>标签
?src的作用 : 加载(包含指定的外部文件)
–可以跨域包含
–被包含的资源可以是任何类型的文件(可以是txt,php等)
–他只关注被包含的文件的内容是否是合法的JS
l原理
?定义函数
?包含外部文件,在被包含的文件中执行调用定义好的函数
?参数的(数据)的实现
–问题:包含就调用,通过动态创建<script>实现按需调用
–问题:包含动态文件时可以通过一个接口实现按需生成调用函数名称

其实,原生JavaScript实现AJAX并不难,这篇文章将会讲解如何实现简单的AJAX,还有跨域请求JSONP!

一、AJAX

AJAX的核心是XMLHttpRequest。

一个完整的AJAX请求一般包括以下步骤:
  ● 实例化XMLHttpRequest对象
  ● 连接服务器
  ● 发送请求
  ● 接收响应数据

我将AJAX请求封装成ajax()方法,它接受一个配置对象params。
function ajax(params) {
  params = params || {};
  params.data = params.data || {};
  // 判断是ajax请求还是jsonp请求
  var json = params.jsonp ? jsonp(params) : json(params);
  // ajax请求
  function json(params) {
    //  请求方式,默认是GET
    params.type = (params.type || ‘GET‘).toUpperCase();
    // 避免有特殊字符,必须格式化传输数据
    params.data = formatParams(params.data);
    var xhr = null;    

    // 实例化XMLHttpRequest对象
    if(window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
    } else {
      // IE6及其以下版本
      xhr = new ActiveXObjcet(‘Microsoft.XMLHTTP‘);
    }; 

    // 监听事件,只要 readyState 的值变化,就会调用 readystatechange 事件
    xhr.onreadystatechange = function() {
      //  readyState属性表示请求/响应过程的当前活动阶段,4为完成,已经接收到全部响应数据
      if(xhr.readyState == 4) {
        var status = xhr.status;
        //  status:响应的HTTP状态码,以2开头的都是成功
        if(status >= 200 && status < 300) {
          var response = ‘‘;
          // 判断接受数据的内容类型
          var type = xhr.getResponseHeader(‘Content-type‘);
          if(type.indexOf(‘xml‘) !== -1 && xhr.responseXML) {
            response = xhr.responseXML; //Document对象响应
          } else if(type === ‘application/json‘) {
            response = JSON.parse(xhr.responseText); //JSON响应
          } else {
            response = xhr.responseText; //字符串响应
          };
          // 成功回调函数
          params.success && params.success(response);
       } else {
          params.error && params.error(status);
       }
      };
    };  

    // 连接和传输数据
    if(params.type == ‘GET‘) {
      // 三个参数:请求方式、请求地址(get方式时,传输数据是加在地址后的)、是否异步请求(同步请求的情况极少);
      xhr.open(params.type, params.url + ‘?‘ + params.data, true);
      xhr.send(null);
    } else {
      xhr.open(params.type, params.url, true);
      //必须,设置提交时的内容类型
      xhr.setRequestHeader(‘Content-Type‘, ‘application/x-www-form-urlencoded; charset=UTF-8‘);
      // 传输数据
      xhr.send(params.data);
    }
  }  

  //格式化参数
  function formatParams(data) {
    var arr = [];
    for(var name in data) {
      //   encodeURIComponent() :用于对 URI 中的某一部分进行编码
      arr.push(encodeURIComponent(name) + ‘=‘ + encodeURIComponent(data[name]));
    };
    // 添加一个随机数参数,防止缓存
    arr.push(‘v=‘ + random());
    return arr.join(‘&‘);
  }

  // 获取随机数
  function random() {
    return Math.floor(Math.random() * 10000 + 500);
  }
}
function ajax(params) {
  params = params || {};
  params.data = params.data || {};
  // 判断是ajax请求还是jsonp请求
  var json = params.jsonp ? jsonp(params) : json(params);
  // ajax请求
  function json(params) {
    //  请求方式,默认是GET
    params.type = (params.type || ‘GET‘).toUpperCase();
    // 避免有特殊字符,必须格式化传输数据
    params.data = formatParams(params.data);
    var xhr = null;    

    // 实例化XMLHttpRequest对象
    if(window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
    } else {
      // IE6及其以下版本
      xhr = new ActiveXObjcet(‘Microsoft.XMLHTTP‘);
    }; 

    // 监听事件,只要 readyState 的值变化,就会调用 readystatechange 事件
    xhr.onreadystatechange = function() {
      //  readyState属性表示请求/响应过程的当前活动阶段,4为完成,已经接收到全部响应数据
      if(xhr.readyState == 4) {
        var status = xhr.status;
        //  status:响应的HTTP状态码,以2开头的都是成功
        if(status >= 200 && status < 300) {
          var response = ‘‘;
          // 判断接受数据的内容类型
          var type = xhr.getResponseHeader(‘Content-type‘);
          if(type.indexOf(‘xml‘) !== -1 && xhr.responseXML) {
            response = xhr.responseXML; //Document对象响应
          } else if(type === ‘application/json‘) {
            response = JSON.parse(xhr.responseText); //JSON响应
          } else {
            response = xhr.responseText; //字符串响应
          };
          // 成功回调函数
          params.success && params.success(response);
       } else {
          params.error && params.error(status);
       }
      };
    };  

    // 连接和传输数据
    if(params.type == ‘GET‘) {
      // 三个参数:请求方式、请求地址(get方式时,传输数据是加在地址后的)、是否异步请求(同步请求的情况极少);
      xhr.open(params.type, params.url + ‘?‘ + params.data, true);
      xhr.send(null);
    } else {
      xhr.open(params.type, params.url, true);
      //必须,设置提交时的内容类型
      xhr.setRequestHeader(‘Content-Type‘, ‘application/x-www-form-urlencoded; charset=UTF-8‘);
      // 传输数据
      xhr.send(params.data);
    }
  }  

  //格式化参数
  function formatParams(data) {
    var arr = [];
    for(var name in data) {
      //   encodeURIComponent() :用于对 URI 中的某一部分进行编码
      arr.push(encodeURIComponent(name) + ‘=‘ + encodeURIComponent(data[name]));
    };
    // 添加一个随机数参数,防止缓存
    arr.push(‘v=‘ + random());
    return arr.join(‘&‘);
  }

  // 获取随机数
  function random() {
    return Math.floor(Math.random() * 10000 + 500);
  }
}

ajax({
  url: ‘test.php‘,   // 请求地址
  type: ‘POST‘,   // 请求类型,默认"GET",还可以是"POST"
  data: {‘b‘: ‘异步请求‘},   // 传输数据
  success: function(res){   // 请求成功的回调函数
    console.log(JSON.parse(res));
  },
  error: function(error) {}   // 请求失败的回调函数
});

二、JSONP

同源策略

AJAX之所以需要“跨域”,罪魁祸首就是浏览器的同源策略。即,一个页面的AJAX只能获取这个页面相同源或者相同域的数据。 如何叫“同源”或者“同域”呢?——协议、域名、端口号都必须相同。例如:
http://example.com  和  https://example.com 不同,因为协议不同;
http://localhost:8080  和  http://localhost:1000 不同,因为端口不同;
http://localhost:8080  和  https://example.com 不同,协议、域名、端口号都不同,根本不是一家的。
当跨域请求时,一般都会看到这个错误:
XMLHttpRequest cannot load http://ghmagical.com/article/?intro=jsonp%E8%AF%B7%E6%B1%82&v=5520. No ‘Access-Control-Allow-Origin‘ header is present on the requested resource. Origin ‘http://localhost‘ is therefore not allowed access.

那如何跨域请求呢?这时,JSONP就登场了!

JSONP(JSON with Padding) 是一种跨域请求方式。主要原理是利用了script 标签可以跨域请求的特性,由其 src 属性发送请求到服务器,服务器返回 JavaScript 代码,浏览器接受响应,然后就直接执行了,这和通过 script 标签引用外部文件的原理是一样的。

JSONP由两部分组成:回调函数和数据,回调函数一般是在浏览器控制,作为参数发往服务器端(当然,你也可以固定回调函数的名字,但客户端和服务器端的名称一定要一致)。当服务器响应时,服务器端就会把该函数和数据拼成字符串返回。
JSONP的请求过程:
  ● 请求阶段:浏览器创建一个 script 标签,并给其src 赋值(类似 http://example.com/api/?callback=jsonpCallback)。
  ● 发送请求:当给script的src赋值时,浏览器就会发起一个请求。
  ● 数据响应:服务端将要返回的数据作为参数和函数名称拼接在一起(格式类似”jsonpCallback({name: ‘abc‘})”)返回。当浏览器接收到了响应数据,由于发起请求的是 script,所以相当于直接调用 jsonpCallback 方法,并且传入了一个参数。

对于JQuery的JSONP请求,这里就不多讲了,之前也写过一篇文章《JQuery的Ajax请求跨域问题》。

在这里讲解一下用原生JavaScript如何实现。

依旧是ajax()方法里添加JSONP,后面会将两者整合在一起,JSONP的配置参数主要多了一个jsonp参数,它就是你的回调函数名。

function ajax(params) {
  params = params || {};
  params.data = params.data || {};
  var json = params.jsonp ? jsonp(params) : json(params);      

  // jsonp请求
  function jsonp(params) {
    //创建script标签并加入到页面中
    var callbackName = params.jsonp;
    var head = document.getElementsByTagName(‘head‘)[0];
    // 设置传递给后台的回调参数名
    params.data[‘callback‘] = callbackName;
    var data = formatParams(params.data);
    var script = document.createElement(‘script‘);
    head.appendChild(script);    

    //创建jsonp回调函数
    window[callbackName] = function(json) {
      head.removeChild(script);
      clearTimeout(script.timer);
      window[callbackName] = null;
      params.success && params.success(json);
    };    

    //发送请求
    script.src = params.url + ‘?‘ + data;    

    //为了得知此次请求是否成功,设置超时处理
    if(params.time) {
     script.timer = setTimeout(function() {
       window[callbackName] = null;
       head.removeChild(script);
       params.error && params.error({
         message: ‘超时‘
       });
     }, time);
    }
  };    

  //格式化参数
  function formatParams(data) {
    var arr = [];
    for(var name in data) {
      arr.push(encodeURIComponent(name) + ‘=‘ + encodeURIComponent(data[name]));
    };   

    // 添加一个随机数,防止缓存
    arr.push(‘v=‘ + random());
    return arr.join(‘&‘);
  }   

  // 获取随机数
  function random() {
    return Math.floor(Math.random() * 10000 + 500);
  } }

意:因为 script 标签的 src 属性只在第一次设置的时候起作用,导致 script 标签没法重用,所以每次完成操作之后要移除;

使用实例:
ajax({
  url: ‘test.php‘,    // 请求地址
  jsonp: ‘jsonpCallback‘,  // 采用jsonp请求,且回调函数名为"jsonpCallbak",可以设置为合法的字符串
  data: {‘b‘: ‘异步请求‘},   // 传输数据
  success:function(res){   // 请求成功的回调函数
    console.log(res);
  },
  error: function(error) {}   // 请求失败的回调函数
});
注意:别漏了用函数名与数据拼接返回。

当然,前面也说过,你可以给定固定回调函数名:
function jsonpCallback() {}

<?php
  echo ‘jsonpCallback(‘.$data.‘)‘;
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文: http://ghmagical.com/article/page/id/AASiankfBJWp ? ghmagical.com

  

时间: 2024-10-10 01:57:12

AJAX jsonp实现过程的相关文章

你不知道的jQuery Item11 -- ajax jsonp跨域方法详解

文章从JSON和JSONP区别开始讲起,用实例来对比他们之间的不同之处,然后详细讲解了jQuery中的ajax jsonp的使用并给出了示例及详细参数说明. 1.JSON和JSONP JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,用于在浏览器和服务器之间交换信息. JSONP(JSON With Padding),就是打包在函数调用中的的JSON(或者包裹的JSON),你要跨域请求别人的东西,你肯定要包裹起来,不要污染了别人的东西,把Json数据包裹

JQuery+ajax+jsonp 跨域访问

Jsonp(JSON with Padding)是资料格式 json 的一种“使用模式”,可以让网页从别的网域获取资料. 关于Jsonp更详细的资料请参考http://baike.baidu.com/view/2131174.htm,下面给出例子: 一.客户端 Html代码   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.

ajax &amp; jsonp &amp; img

ajax 是一种请求服务器的方式,核心是XMLHttpRequest对象: 优点是无需刷新页面, 缺点是不能跨域请求. /* * Ajax direacted by Zakas * * Ajax.get("url?p=value", function (data) { // handle data }, false); * * Ajax.post("url",{ * data : "p=value&id=001", * callback

项目中关于ajax jsonp的使用

项目中关于ajax jsonp的使用,出现了问题:可以成功获得请求结果,但没有执行success方法总算搞定了,记录一下 function TestAjax() {    $.ajax({        type : "get",        async : false,        url : "ajaxHandler.ashx", //实际上访问时产生的地址为: ajax.ashx?callbackfun=jsonpCallback&id=10   

PHP AJAX JSONP实现跨域请求使用实例

在之前我写过“php返回json数据简单实例”,“php返回json数据中文显示的问题”和“在PHP语言中使用JSON和将json还原成数组”.有兴趣的童鞋可以看看 今天我写的是PHP AJAX JSONP使用的实例.不清楚jsonp是什么的请自己搜索 实例1 test.html <!doctype html> <html> <head> <meta charset="utf-8"> <title>test</title

jquery ajax jsonp跨域调用实例代码

今天研究了AJAX使用JSONP进行跨域调用的方法,发现使用GET方式和POST方式都可以进行跨域调用,这里简单分享下,方便需要的朋友 客户端代码 复制代码 代码如下: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApp.WebForm1" %><!DOCTYPE html P

跨域请求之jQuery的ajax jsonp的使用解惑

转自:http://www.cnblogs.com/know/archive/2011/10/09/2204005.html 前天在项目中写的一个ajax jsonp的使用,出现了问题:可以成功获得请求结果,但没有执行success方法,直接执行了error方法提示错误——ajax jsonp之前并没有用过,对其的理解为跟普通的ajax请求差不多,没有深入了解:出现了这种错误,几经调试(检查后台的代码和js部分的属性设置)还是不行,让我感觉很是意外和不解.于是,决定仔细研究下ajax jsonp

jQuery源码分析系列(35) : Ajax - jsonp的实现与原理

ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本 json核心就是:允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了. jquery ext dojo这类库的实现手段其实大同小异 在同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,但img.iframe.s

ajax jsonp函数调用

jsonp数据 jsonpHandler({name:"liujinyu",age:"24"}) ajax调用 $.ajax({    type:'GET',    url:"http://10.14.85.90/data/people.html",    dataType:'jsonp',    cache:true,    async:true,    //jsonp: "jsonpHandler",//传递给请求处理程序