手写Ajax(JSONP)

参考:原生 JavaScript 实现 AJAX、JSONP

XMLHttpRequest的使用

参考:XMLHttpRequest
XMLHttpRequest发送请求和获取响应

例子:

var request = new XMLHttpRequest();
request.open("GET", "get.php", true);
request.send();
//该属性每次变化时会触发
request.onreadystatechange = function(){
    //若响应完成且请求成功
    if(request.readyState === 4 && request.status === 200){
        //do something, e.g. request.responseText
    }
}

发送请求:

  1. 建立XMLHttpRequest对象:var request = new XMLHttpRequest();
  2. .open初始化请求:request.open(方法名, URL, 是否异步);
  3. .send(data)发送数据:request.send(data);

监听回复:

​ 1.服务器回复之后readystate变化,调用onreadystatechange

​ 2.根据readystate请求状态码,status服务器返回的响应状态。处理请求成功之后服务器返回的数据

不考虑json的ajax

ajax的使用方式:

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

需求分析:

​ 根据type的不同发送不同请求,根据服务器返回的状态调用susccess请求成功,error请求失败函数

function  ajax(params) {
    let {method='GET',data={},url,success=function () {},error=function () {}}=params
    let request = new XMLHttpRequest()
    request.open(method,url,true)
    request.send(data)
    request.onreadystatechange=function () {
        if(request.readyState === 4){
            let status = request.status
            if(request.status>=200&&request.status<300){
                success(request.responseText,request.responseXML)
            }else {
                error(status)
            }
        }
    }
}

功能完善:

​ 1.为保证服务器接收数据正确,如果数据类型为key1=val1&key2=val2时客户端所发送的数据都要经encodeURIComponent进行编码。

​ 也就是:1.1发送GET请求

​ 1.2发送POST请求的Content-Type='application/x-www-form-urlencoded'

​ 2.GET方法send(null),POST方法根据Content-Type的不同发送不同的数据数据类型

​ 本例中的Content-Type可为:application/jsonapplication/x-www-form-urlencoded

let TYPE_URLENCODED='application/x-www-form-urlencoded'
let TYPE_JSON = 'application/json'
function  ajax(params) {
    let method = params.method.toUpperCase()||'GET'
    let data = params.data||{}
    let url = params.url
    let success = params.success||function () {}
    let error =params.error||function () {}
    let contentType = params.contentType||'application/x-www-form-urlencoded'
    if(!url){
        console.log('url can\'t be undefined')
        return
    }

    const request = new XMLHttpRequest()

    function urlEncodeFormat(data){
        let encoded=[]
        for (let key in data){
           let unit=encodeURIComponent(key)+'='+encodeURIComponent(data[key])
               encoded.push(unit)
        }
        return encoded.join('&')
    }

    if(method==='GET'){
        data=urlEncodeFormat(data)
        debugger
        let url=params.url+'?'+data
        request.open(method,url,true)
        request.send(null)

    }else if(method==='POST'){
        request.open('POST',url,true)
        if(contentType === TYPE_URLENCODED){
            data=urlEncodeFormat(data)
        }else if( contentType === TYPE_JSON){
            data=JSON.stringify(data)
        }
        request.setRequestHeader('Content-Type',contentType)
        request.send(data)
    }
    request.onreadystatechange = function () {
        if (request.readyState === 4){
            if(request.status>=200&& request.status<300){
                success(request.responseText,request.responseXML)
            }else{
                error(request.status)
            }
        }
    }
}

//使用示例
let baseURL='http://localhost:3333'
ajax({
    url:baseURL+'/getTest',
    method:'GET',
    data:{
        name:'get data',
        data:'gggg'
    },
    success:function (data) {
        console.log(data)
    },
    error:function (err) {
        console.log(err)
    }
})

ajax({
    url:baseURL+'/postTest',
    method:'POST',
    data:{
        name:'post data',
        data:'ppppppp'
    },
    success:function (data) {
        console.log(data)
    },
    error:function (err) {
        console.log(err)
    }
})

ajax({
    url:baseURL+'/postTest',
    method:'POST',
    contentType:'application/json',
    data:{
        name:'post data',
        data:'jjjjj'
    },
    success:function (data) {
        console.log(data)
    },
    error:function (err) {
        console.log(err)
    }
})

JSONP

JSONP原理:1.<script>标签不受同源政策影响,可以跨域根据scr的地址请求资源

​ 2.1用<sctipt>标签请求到的是javascript代码,相当于浏览器直接请求到了这段代码并且执行。服务器向客户端jsonp传参就是在返回的javasctipt代码的函数中传参,类似jsonpCallBack({data:'ddddd'})

​ 2.2 succuss: jsonpCallBack在发送请求前被声明,会拿到服务器返回的参数,调用success(data),将参数传给success

​ 2.3 error:由于没有使用XMLHttpRequest,所以无法根据服务器返回状态调用error——>设置超时定时器,如果一段时间内没有调用jsonpCallBack成功调用success说明超时、请求错误

仅仅实现了客户端,服务端PHP请参考:原生 JavaScript 实现 AJAX、JSONP

let TYPE_URLENCODED='application/x-www-form-urlencoded'
let TYPE_JSON = 'application/json'
function  ajax(params) {
    let data = params.data||{}
    let url = params.url
    let success = params.success||function () {}
    let error =params.error||function () {}
    let jsonpCbCount=0
    if(!url){
        console.log('url can\'t be undefined')
        return
    }

    function urlEncodeFormat(data){
        let encoded=[]
        for (let key in data){
            let unit=encodeURIComponent(key)+'='+encodeURIComponent(data[key])
            encoded.push(unit)
        }
        return encoded.join('&')
    }

    function normalRequest() {
        let method = params.method.toUpperCase()||'GET'
        let contentType = params.contentType||'application/x-www-form-urlencoded'
        const request = new XMLHttpRequest()

        if(method==='GET'){
            data=urlEncodeFormat(data)
            let url=params.url+'?'+data
            request.open(method,url,true)
            request.send(null)

        }else if(method==='POST'){
            request.open('POST',url,true)
            if(contentType === TYPE_URLENCODED){
                data=urlEncodeFormat(data)
            }else if( contentType === TYPE_JSON){
                data=JSON.stringify(data)
            }
            request.setRequestHeader('Content-Type',contentType)
            request.send(data)
        }
        request.onreadystatechange = function () {
            if (request.readyState === 4){
                if(request.status>=200&& request.status<300){
                    success(request.responseText,request.responseXML)
                }else{
                    error(request.status)
                }
            }
        }
    }

    function jsonpRequest() {
        let method = 'GET'
        let timeout=params.timeout||1000
        let data = params.data||{}
        let jsonpCbFn='jsonpCb'+jsonpCbCount//每次jsonp请求返回的script调用的函数都是唯一的
        jsonpCbCount++

        //添加script发送请求
        data.jsonpCbFn=jsonpCbFn
        data= urlEncodeFormat(data)
        let script = document.createElement('script')
        script.src=params.url+'?'+data
        let head=document.getElementsByTagName('head')[0]
        head.appendChild(script)

        //定义服务器返回数据时调用的函数
        window[jsonpCbFn] = function (res) {
            clearTimeout(timer)
            head.removeChild(script)
            success(res)
        }

        let timer = setTimeout(function () {
            head.removeChild(script)
            params.error('jsonp error,timeout:'+timeout)
        },timeout)
    }

    params.jsonp?jsonpRequest():normalRequest()

}

//使用示例
let baseURL='http://localhost:3333'
ajax({
    url:baseURL+'/jsonpTest',
    jsonp:true,
    data:{
        name:'jsonp',
        data:'jsonp/jsonp/jsonp'
    },
    success:function (data) {
        console.log(data)
    },
    error:function (err) {
        console.log(err)
    }
})

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容