34-高级:AJAX入门

前言:
预习:http://javascript.ruanyifeng.com/bom/ajax.html

完整代码:https://github.com/FrankFang/nodejs-test-cors

金句:

  1. 你才返回对象,你全家都返回对象
  2. JS 是一门语言,JSON 是另一门语言,JSON 这门语言抄袭了 JS这门语言
  3. AJAX 就是用 JS 发请求
  4. 响应的第四部分的类型是字符串,可以用 JSON 语法表示一个对象,也可以用 JSON 语法表示一个数组,还可以用 XML 语法,还可以用 HTML 语法,还可以用 CSS 语法,还可以用 JS 语法,还可以用.........

回顾上一节:
如何发请求?
用 form 可以发请求,但是会刷新页面或新开页面
用 a 可以发 get 请求,但是也会刷新页面或新开页面
用 img 可以发 get 请求,但是只能以图片的形式展示
用 link 可以发 get 请求,但是只能以 CSS、favicon 的形式展示
用 script 可以发 get 请求,但是只能以脚本的形式运行

有没有什么方式可以实现:

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

本节,将介绍一种方法,可以解决上面问题。

一、用XMLHttpRequest发请求


  1. XMLHttpRequest的产生:IE 5 率先在 JS 中引入 ActiveX 对象(API),使得 JS 可以直接发起 HTTP 请求。随后 Mozilla、 Safari、 Opera 也跟进(抄袭)了,取名 XMLHttpRequest,并被纳入 W3C 规范。
    XMLHttpRequest 是window 下的一个全局对象,也是一个构造函数。


    image.png

二、AJAX


Jesse James Garrett 将如下技术取名叫做 AJAX:异步的 JavaScript 和 XML;
一个完整的AJAX要具备以下3点:

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

尝试用JS写一个符合上面3点要求的请求:
server-ajax.js:


    }else if(path === '/xxx'){

      response.setHeader('Content-Type','application/xml')
      response.statusCode = 200
      response.write(`
      <note>
        <to>小明</to>
        <from>老王</from>
        <heading>问候</heading>
        <body>Hi,我在你隔壁</body>
      </note>
      `)
      response.end()
    }

html:

<body>
    <h5>你的账户余额是:<span id="amount">&&&amount&&&</span></h5>
    <button id="button">付款1块钱</button>

    <script>
        button.addEventListener('click',(e)=>{
            let request = new XMLHttpRequest() //1-构造一个XMLHttpRequest
            request.onreadystatechange = ()=>{ //监听readystate的变化
                if(request.readyState === 4){
                    console.log('请求响应完毕')
                    if(request.status >= 200 && request.status < 300 ){
                        console.log('请求成功')
                        console.log(request.responseText)
                        let parser = new DOMParser()
                        let xmlDoc = parser.parseFromString(request.responseText,"text/xml")
                        let title = xmlDoc.getElementsByTagName('heading')[0].textContent
                        console.log(title)
                    }else if(request.status >= 400){
                        console.log('请求失败')
                    }
                }
            }
            // console.log(request.readyState) //结果:0
            request.open('GET','/xxx') //2-设定request,请求方式,URL,是否异步...,默认是异步;即便实际请求的文件路径为'./xxx'但是http在发请求是还是会强制变更为符合http的路径(绝对路径),
            // console.log(request.readyState) //结果:1
            request.send() //3-发送请求
            // setInterval(()=>{
            //     console.log(request.readyState)
            // },1) //结果:1, 4;中间状态未能捕捉到
        })
    </script>
</body>

以上的就是一个符合AJAX的完整的JS代码。
将其整理修剪后的简洁的代码:

<script type="text/javascript">
    let ajaxRequest = new XMLHttpRequest()
    ajaxRequest.open('get','/xxx')
    ajaxRequest.send()
    ajaxRequest.onreadystatechange = ()=>{
        if (ajaxRequest.readyState ==== 4) {
            if (ajaxRequest.status >= 200 && ajaxRequest.status < 300) {

                let string = ajaxRequest.responseText
                let object = window.JSON.parse(string)
            }
        }
    }
</script>
  • XMLHttpRequest.readyState
    XMLHttpRequest.readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态。一个 XHR 代理总是处于下列状态中的一个:
状态 描述
0 UNSENT 代理被创建,但尚未调用 open() 方法。
1 OPENED open() 方法已经被调用。
2 HEADERS_RECEIVED send() 方法已经被调用,并且头部和状态已经可获得。
3 LOADING 下载中; responseText 属性已经包含部分数据
4 DONE 下载操作已完成。

三、XML和JSON


  1. JSON-----JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
    JSON是一门新语言,并不是一个JavaScript对象,只不过是仿JavaScript编写的。
    JSON的数据格式规范----JSON官网
    • JSON VS JS
      1. JSON只有 string,number,object,array,true,false,null 这7种类型。JavaScript的基本类型中,undefined,symbol,function这3种没有抄;
      2. JSON 的字符串首尾必须是双引号:"";

举例:

JS VS JSON
undefined 没有
null null
['a',"b"] ["a","b"]
function fn(){} 没有
var a={};a.self=a; 搞不定,没有变量
{__proto__} 没有原型链

2. XML 与 JSON
来个例子:
返回XML格式的字符串:

      response.setHeader('Content-Type','application/xml;charset=utf-8')
      response.write(`
      <note>
        <to>小明</to>
        <from>老王</from>
        <heading>问候</heading>
        <body>Hi,我在你隔壁</body>
      </note>
      `)

返回JSON格式的字符串:

response.setHeader('Content-Type','application/json;charset=utf-8')
response.write(`
{
    "note":{
        "to":"小明",
        "from":"老王",
        "heading":"问候",
        "body":"Hi,我在你隔壁"
    }
}
`)

以上两种返回的内容在类型上都是字符串,只是书写格式符合XML和JSON;也就是说前端收到的都只是一堆字符串。

那么,前端如何以符合XML和JSON的格式应用这一堆字符串??

<script type="text/javascript">
    button.addEventListener('click',(e)=>{
        let request = new XMLHttpRequest()
        request.onreadystatechange = ()=>{
            if(request.readyState === 4){
                console.log('请求响应完毕')
                if(request.status >= 200 && request.status < 300 ){
                    console.log('请求成功')
                    console.log(typeof request.responseText) //string
                    console.log(request.responseText)
                    // let parser = new DOMParser()
                    // let xmlDoc = parser.parseFromString(request.responseText,"text/xml")
                    // let title = xmlDoc.getElementsByTagName('heading')[0].textContent
                    // console.log(title)

                    let string = request.responseText
                    // 把符合 JSON 语法的字符串
                    // 转换成 JS 对应的值
                    let object = window.JSON.parse(string)
                    // JSON.parse 是浏览器提供的
                    // document.getElementById 是浏览器提供的
                    console.log(typeof object) //此时已经是 Object
                    console.log(object)
                }else if(request.status >= 400){
                    console.log('请求失败')
                }
            }
        }

        request.open('GET','/xxx')
        request.send()

    })
</script>

四、同源策略与CORS跨域


  • 问题:为什么form表单提交没有跨域问题,而ajax提交有跨域问题???
    测试:
  1. 用form表单发一个跨网站的请求(记得勾选preserve log):
<body>
    <form action="https://www.baidu.com" method="GET">
        <input type="password" name="password">
        <input type="submit">
    </form>
</body>

测试1结果:点击提交后,页面跳转https://www.baidu.com,响应状态码为200,成功,如果是用POST,百度会响应302;

  1. 用AJAX发一个跨网站的请求(记得勾选preserve log):
<script type="text/javascript">
    let ajaxRequest = new XMLHttpRequest()
    ajaxRequest.open('get','https://www.baidu.com')
    ajaxRequest.send()
    ajaxRequest.onreadystatechange = ()=>{
        if (ajaxRequest.readyState ==== 4) {
            console.log('请求响应完毕')
            console.log(request.status)
            if (ajaxRequest.status >= 200 && ajaxRequest.status < 300) {

                let string = ajaxRequest.responseText
                let object = window.JSON.parse(string)
            }
        }
    }
</script>

测试2结果:点击提交后,页面并没有跳转到https://www.baidu.com,但是响应状态码为200,请求成功;查看响应内容发现为空;打印status结果为0;控制台有报错:

image.png

这就是AJAX的同源策略导致的结果;form,img,a,script,link都可以跨站请求,只有ajax只能同源请求,原因????

因为原页面用 form 提交到另一个域名之后,页面会跳转到新页面,原页面就死了,原页面的脚本无法获取新页面的内容。
所以浏览器认为这是安全的。
而 AJAX 是可以读取响应内容的,因此浏览器不允许你这样做;
如果你细心的话会发现,其实请求已经发送出去了,只是拿不到响应而已。
所以,浏览器的这个策略的本质是,一个域名的JS,在未经允许的情况下,不得读取另一个域名的内容。但浏览器并不阻止你向另一个域名发送请求。

怎么解决跨站?????

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

推荐阅读更多精彩内容