是我
lllhy

Ajax与JS实现及跨域问题

概述

Ajax(Asynchronous JavaScript and XML),AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

XMLHttpRequest

js中实现Ajax是基于XMLHttpRequest对象实现的,我们首先来看下如何使用XMLHttpRequest对象发起一个http请求。

发起一个请求

我们先回忆一下,一个完整的HTTP请求需要的是:

  • 请求的网址、请求方法GET/POST。
  • 提交请求的内容数据、请求主体等。
  • 接收响应回来的内容。

使用XMLHttpRequest对象发起请求与之类似。

  • 创建XMLHttpRequest对象
  • 调用open方法设置请求内容
  • 调用send方法发起请求
  • 注册onreadystatechange事件
  • 获取返回的数据。

下面我们先看个例程吧。

/*
 * 使用XMLHttpRequest发起一个异步GET请求。
 */
// 实例化一个XMLHttpRequest对象
var xhr = new XMLHttpRequest();
// 调用open方法设置请求内容
xhr.open('get','https://lllhy.com',async=true);
// 调用send方法发起请求
xhr.send();
// 注册onreadystatechange事件
xhr.onreadystatechange = function(){
    console.log(ajax.status);
    console.log(ajax.readystate)
    console.log('state change!')
}

相信你已经对XMLHttpRequest对象的使用已经有了一定的了解,接下来我们具体看看XMLHttpRequest吧。

详解

请求头

通过使用setRequestHeader方法设置请求头,如

xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

请求体

当发送POST请求时,调用send方法时可选择传入参数作为请求体。

xhr.send('name=fox&age=18');

相应状态

相信你再第一个例程中已经看到了。onreadystatechange事件并不只会在请求完成时触发,而是每次readystate状态变更时触发。

readystate状态有以下几种:

  • 0:请求未初始化
  • 1:服务器连接已建立
  • 2:请求已接收
  • 3:请求处理中
  • 4:请求处理完成,相应已就绪

也就是只有当readystate为4时才表示相应已经就绪,所以我们在注册onreadystatechange事件时需要注意readystate是否为4

解析数据

我们最常接触到的相应数据有两种,JSON格式相应和XML相应,我们分别看下需要怎么解析这两种相应。

XML数据解析

我们可以通过responseXML查看相应的XML格式的数据。如下

var xhr = new XMLHttpRequest();

xhr.open('get','get_XMl.php');

xhr.send();

xhr.onreadystatechange = function () {
    if (xhr.readyState == 4 && xhr.status==200) {
        // 如果 返回的是 xml文件
        console.log(xhr.responseText);

        // 异步 对象中 有另外一个属性 用来专门获取 xml
        // xml对象 在浏览器段 就是一个 document对象
        // 解析时 可以直接使用 querySelector 或者 getElementById等等 document对象 有的语法
        console.log(xhr.responseXML);
        console.log(xhr.responseXML.querySelector('kuzi').innerHTML);
        // 下面这个 页面文档对象 如果要获取某个标签
        console.log(window.document);
    }
}
JSON数据解析

JSON数据解析时需要使用JSON.prase解析,并且需要将相应内容看作text读取,如下

var xhr = new XMLHttpRequest();

xhr.open('get','myJson.php');

xhr.send();

xhr.onreadystatechange = function () {
    if (xhr.readyState==4&&xhr.status==200) {
        // json 字符串 是字符串 所以我们可以 通过  responseText获取
        console.log(xhr.responseText);

        // 转化为 js对象
        var jsObj = JSON.parse(xhr.responseText);
        console.log(jsObj);
    }
}

手动实现JQuery中的Ajax方法

JQuery中的Ajax同样时基于XMLHttpRequest的,所以我们可以手工实现一个ajax方法。

大致思路为初始化请求参数,然后实例化XMLHttpRequest对象,使用XMLHttpRequest发送请求,最终对onreadystatechange中readystate进行判断,调用对应的回调函数。

function ajax(settings){
    settings = initSettings(settings);
    try{
        var xhr = new XMLHttpRequest();
        // 建立连接
        xhr.open(settings.type,settings.url,settings.ansyc);
        // beforeSend
        settings.beforeSend(xhr);
        // send
        xhr.send(settings.data);
        // onreadystatechange 事件
        xhr.onreadystatechange=function(){
            if(xhr.readyState==4){
                settings.complete(xhr, "success");
                if(xhr.status != 200){
                    settings.error(xhr.status);
                    return;
                }
                // success
                settings.success(xhr.responseText, xhr.responseXML);
            }
        }
    }catch(e){
        settings.error(e);
    }
}

// 初始化请求参数
function initSettings(settings){
    defaultSettings = {
        type: "get",
        url: "https://lllhy.com",
        ansyc: true,
        beforeSend: function(xhr){},
        onreadystatechange: function(){},
        complete: function(xhr, ts){},
        contentType: "application/x-www-form-urlencoded",
        context: settings,
        data: {},
        success: function(responseText,responseXML){},
        error: function(e){console.log("request error: "+e);}    
    };
    //使用settings更新defaultSettings
    for(key in settings){
        defaultSettings[key] = settings[key];
    }
    defaultSettings.data = formatParams(defaultSettings.data);
    if(defaultSettings.type === "get"){
        defaultSettings.url = defaultSettings.url+"?"+defaultSettings.data;
        defaultSettings.data = null;
    }    
    return defaultSettings;
}
// 格式化请求参数
function formatParams(data){
    var arr=[];
    for(var name in data){
        arr.push(encodeURIComponent(name)+"="+encodeURIComponent(data[name]));
    }
    arr.push(("v="+Math.random()).replace(".",""));
    return arr.join("&");
}

上面实现了一个非常简陋版本的Ajax方法。但是对于XMLHttpRequest对象以及ajax异步请求一定会有更深入的了解。

同源策略与跨域(CORS,Cross-origin resource sharing)

有的浏览器都遵守同源策略,这个策略能够保证一个源的动态脚本不能读取或操作其他源的http响应和cookie,这就使浏览器隔离了来自不同源的内容,防止它们互相操作。所谓同源是指协议、域名和端口都一致的情况。简单的来说,出于安全方面的考虑,页面中的JavaScript无法访问其他服务器上的数据,即“同源策略”。而跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果。

https://img.lllhy.com/pic_bed/20210404112822.png

跨域问题解决办法

跨域问题有两种解决办法:一种是通过CORS添加Access-Control-Allow-Origin的源站,并且在请求头中添加origin达到跨域请求的目的;还一种就是通过JSONP方式发起跨域请求。

JSONP

JSONP的主要思路如下:

由于AJAX不允许跨域请求,同时我们发现HTML标签中src不受跨域限制。如果我们通过<script>scr属性设置我们需要访问的请求地址,同时将服务器返回设置为一行调用callback函数的JS语句。也就是将返回的数据传递给callback,由此我们就完美避开跨域问题且获取到了服务器的返回值。

看个例子:

<script type="text/javascript">
    function callbackFunction(data){
        //data内容就是服务器返回的数据
        console.log(data);
    }
    // 通过JSONP的方式发起跨域请求
    var url = "https://lllhy.com" + "?callback=callbackFunction";
    var script = document.createElement("script");
    script.setAttribute("src",url);
    // 将标签加入dom
    document.getElementsByTagName("head")[0].appendChild(script);

    // 那么服务器端的返回应该如下,调用callback,并传入数据
    callbackFunction({"data":"result data"})
<script>

服务器如果支持JSONP,那么最终会返回一个JS语句,来调用回调设置的回调函数,并且将服务器返回的数据作为参数,传递进去。

赞赏

lhy

文章作者

普通人。

发表评论

textsms
account_circle
email

lllhy

Ajax与JS实现及跨域问题
概述 Ajax(Asynchronous JavaScript and XML),AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面…
扫描二维码继续阅读
2021-04-04