AJAX原理和实现方式

JSONP发展

了解了JSONP技术栈后,知道了JSONP是AJAX出现之前后端交互最好的解决方案,但它依然没解决问题,用JSONP只能发送GET请求,不能发其他请求

form表单可以发GET请求,也可以发POST请求,POST请求没有请求参数,但是会刷新页面或新开页面

<form action="/xxx" method=get>
    <input type="password" name="password">
    <input type="submit">
</form>

a标签可以发GET请求,会刷新页面或新开页面

<a id="x" href="/xxx">
<script>    //进入页面就会自动点a标签
    x.click()
</script>

img标签可以发GET请求,只能以图片方式展示

let image = document.createElement('img')
img.src = '/xxx'
imgae.onload = () => {}
imgae.onerror = () => {}

link可以发GET请求,但是只能以CSS、favicon的形式展示

let link = document.createElement('link')
link.src = '/xxx'
document.head.appendChild(link)
link.onload = () => {}
link.onerror = () => {}

用script可以发GET请求,但是只能以脚本的形式运行

let script = document.createElement('script')
script.src = '/xxx'
document.body.appendChild(script)
script.onload = () => {}
script.onerror = () => {}

有没有什么方式可以实现

  1. get、post、put、delete请求都行
  2. 想以什么形式展示就以什么形式展示

微软的突破
IE 5 率先在 JS 中引入 ActiveX 对象(API),使得 JS 可以直接发起 HTTP 请求。
随后 Mozilla、 Safari、 Opera 也跟进(抄袭)了,取名 XMLHttpRequest,并被纳入 W3C 规范

AJAX

AJAX 全称 Async Javascript and XML 翻译成中文:异步的 JavaScript 和 XML

Ajax 技术的核心是 XMLHttpRequest 对象(简称:XHR),可以在不刷新页面页面也能取得新的数据。

满足下面的条件就是AJAX

  1. 使用 XMLHttpReques 发请求
  2. 服务器返回 XML 格式的字符串
  3. JS 解析 XML,并更新局部页面

XMLHttpRequest 的用法

使用 XMLHttpRequest 三步骤:

  1. 要用 XMLHttpRequest 构造一个对象
  2. 调用 open() 方法
  3. 调用 send() 方法

open() 方法接收三个参数:请求类型,请求 url,是否使用异步;
send() 方法接受一个参数:请求主体发送的数据。

这个请求是同步的,浏览器会等到服务器响应之后继续执行,响应之后的相关属性:
responseText:响应主体返回的文本
status:响应的 HTTP 状态
statusText:响应的 HTTP 状态说明

在接收到响应后,应该这样检查两种状态

let request = new XMLHttpRequest()
request.onreadystatechange = function(e){
    if(request.status >= 200 && request.status < 300 || request.status === 304){
        console.log(request.responseText)
    }else if(request.status >=400){
        console.log("错误信息:" + request.status)
    }
}
request.open('POST','http://jack.com:8889/xxx')
request.send()

大多数情况下,我们使用的是异步请求,才能 JS 继续执行,不必等待响应,此时应该检查readyState,这个属性有5种取值:

状态描述
0UNSENT(未打开)open()方法还未被调用
1OPENED(未发送)send()方法还未被调用
2HEADERS_RECEIVED(以获取响应头)send()方法已经被调用,响应头和响应状态已经返回
3LOADING(正在下载响应体)响应体下载中;responseText中已经获取部分数据
4DONE(请求完成)整个请求过程已完毕

只要readyState属性值一变化,就会触发一次readystatechange事件,可以利用这个事件来检测每次状态变化后的readystate的属性值,通常我们只对readystate值为4进行检测。

let request = new XMLHttpRequest()
request.onreadystatechange = function(e){
    if(request.readyState === 4){
        if(request.status >= 200 && request.status <= 300){
            console.log(request.responseText)
        }else if(request.status >=400){
            console.log("错误信息:" + request.status)
        }
    }
}
request.open('POST','http://jack.com:8889/xxx')
request.send()

响应返回的requestText永远是字符串,早期使用的符合 XML 格式的字符串,现在使用的是符合 JSON 语法的字符串,前端拿到后可以用window.JSON.parse()来解析

具体来看一个例子:点击按钮发送一个 POST 请求

<button id="myButton">点我</button>
myButton.addEventListener('click',function(){
    let request = new XMLHttpRequest()
    request.onreadystatechange = function(){    //尽量往上放,不会错过任何一个状态,放在下面的话会错过之前的状态
        console.log(request.readyState)
        if(request.readyState === 4){        //请求完成
            if(request.status === 200){            //请求成功
                let string = request.responseText
                //把符合 JSON 语法的String 转换成 JS 对应的 Object
                let object = window.JSON.parse(string)    //JSON.parse 是浏览器提供的,json3.js是著名的就是写JSON.parse的
            }else if(request.status === 400){    //请求失败
                console.log("错误信息:" + request.status)
            }
        }
    }
    request.open('POST','http://jack.com:8889/xxx')    //配置 request
    request.send()
})

服务器上面就要这样写

if(path === '/xxx' && method === 'POST'){
    response.setHeader('Content-Type','text/json;charset=utf-8')
    response.write(`        //JSON语法
        {            //Http第四部永远是 String,这里是符合 JSON 语法的
 String,不是 Object
            "note":{
                "to":"张三",
                "from":"李四",
                "heading":"打招呼",
                "content":"hi"
            }
        }
    `)
}

JavaScript 和 JSON 语法的不同之处

JSJSON
undefined没有
nullnull
[‘a’,’b’][“a”,”b”]
function{}没有
{name:’frank’}{“name”:”frank”}
‘frank’“frank”
var a = {};a.self = a搞不定(没有变量)
{__proto__}没有原型链

跨域资源共享

Ajax 通信只能访问同一个域下的资源,简单的说如果不是同一个网站,不能送 AJAX 请求,它是状态码status为0。

只有协议+端口+域名一模一样才允许发 AJAX 请求

因为 AJAX 可以读取响应内容,因此浏览器不允许你这样做

有时也需要合理的跨域请求,有两种方法:

  1. SRJ方案
  2. CORS方案

SRJ 方案之前已经讲过了,这里不在重复,可以看:JSONP技术栈

这里讲解一个 CORS(Cross-Origin Resource Sharing,跨域源资源共享),基本思想就是使用自定义的 HTTP 响应头:

在服务器上,共享的资源加上响应头
response.setHeader('Access-Control-Allow-Origin','http://jack.com:8889')就可以了。

如果没有这个头部,或者有这个信息但源信息不匹配,请求还是成功,但服务器给的响应没有响应体(第四部分)。注意:请求和响应都不包含 Cookie 信息。

    原文作者:UCCs
    原文地址: https://segmentfault.com/a/1190000015068740
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞