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种取值:

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

只要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 语法的不同之处

JS JSON
undefined 没有
null null
['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 信息。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容