美文网首页
34-高级:AJAX入门

34-高级:AJAX入门

作者: 格林姆大师 | 来源:发表于2018-08-22 14:49 被阅读0次

    前言:
    预习: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')

    相关文章

      网友评论

          本文标题:34-高级:AJAX入门

          本文链接:https://www.haomeiwen.com/subject/qgugbftx.html