看完这篇文章,你将了解

1.XMLHttpRequest 对象简要
2.JSON 简要
3.原生 js 如何实现 JSONP
4.原生 js 如何实现 AJAX
5.同源策略与 CORS 跨域
6.其他小知识


一. 预备知识 XMLHttpRequest对象简要

属性:

xhr.responseText    //收到的响应字符串
xhr.status         //响应的状态码(200 404 ...)
xhr.readystate    //响应下载状态0-4(含义见 六=>3)

方法:

xhr.open('GET', '/xxx')                 //配置请求动作与路径
xhr.setHeader('content-type', 'yyy')    //配置请求头
xhr.send()                              //发送请求
xhr.onreadystatechange() = function(){} //监听响应下载状态

二. 预备知识 JSON简要

1.基本类型

string number boolean null object array

注意:JSON的字符串类型必须加双引号 " "

2.服务器怎么返回对象给前端?

a:服务器其实不能返回对象给前端,只能返回字符串给前端(因为HTTP响应的第四部分永远是字符串),只不过当这个字符串符合JSON对象语法时,我们可以解析出对象。

3.字符串解析为JSON对象:

let object = window.JSON.parse(string)

三. JSONP

1.什么是JSONP?

简易版:JSONP就是请求一个script,然后运行这个script。

完整版:JSONP(JSON with padding)是数据格式JSON的一种“使用模式”,可以让网页从别的网域要数据。

主要目的是实现页面与后端的无刷新交互

主要方法是:动态创建script标签并让src指向后端,后端返回脚本内容,触发浏览器立即加载并执行相应js代码,从而实现前后端无刷新数据交互。

2.JSONP 具体写法

就是前端提供函数的定义和script,后端提供实参和调用语句。

  • 请求方:创建script,src指向响应方,同时传一个查询参数?callback = xxx(xxx是请求方的一个函数)
  • 响应方:根据查询参数callback获得xxx,传入数据,并返回一条调用xxx函数的js命令
  • xxx这个函数名由 字符串+随机数 组成
  • 监听script脚本的加载事件,无论成功与否,干掉这个脚本和随机函数

3.示例

前端代码:

button.addEventListener('click', (e)=>{
    let functionName = 'frank' + parseInt(Math.random()*10000000, 10)
    window[functionName] = function(result){ //每次请求之前搞出一个随机的函数名
        if(result === 'success'){
            amount.innerText = amount.innerText - 0 - 1
        }
    }
    let script = document.createElement('script')
    script.src = '/pay?callbacck=' + functionName
    document.body.appendChild(script)
    script.onload = function(e) { //状态码是200-299,则表示成功
        e.currentTarget.remove() //请求完了就干掉这个脚本
        delete window[functionName]     //请求完了就干掉这个随机函数
    }
    script.onerror = function(e) { //请求码大于等于 400 则表示失败
        e.currentTarget.remove()
        delete window[functionName]
    }
})

后端代码:

...
if( path === '/pay') {
    let amount = fs.readFileSync('./db', 'utf8')
    amount -= 1
    fs.writeFileSync('./db', amount)
    let callbackName = query.callback
    response.setHeader('Content-Type', 'application/javascript')
    response.write(`
        $(callbackName).call(undefined, 'success')
    `)
    response.end()
}
...

四. AJAX

  • 什么是AJAX?

    • 简易版:就是用原生的XMLHttpRequest对象发出请求,得到服务器返回的数据后再作处理。
    • 完整版:完整写法为async Javascript and XML:异步的javascript和XML。满足三个要求即为AJAX:

      • 使用XMLHttpRequest(xhr)发请求
      • 服务器返回XML格式的字符串
      • JS解析XML,并局部更新页面
  • 原生js实现AJAX

    submit.onclick = function(){
        let xhr = new XMLHttpRequest()
        xhr.open('POST', '/pay') //配置xhr
        xhr.send()
        xhr.onreadystatechange() = function() {
            if(xhr.readyState === 4) {
                if(xhr.status >=200 && xhr.status < 300) {
                    console.log('请求成功')
                    let str = xhr.responseText
                    let obj = JSON.parse(str)
                    console.log(obj)
                }else if(xhr.status >= 400) {
                    console.log('请求失败')
                }
            }
        }
    }

五. 扩展知识:同源策略与CORS跨域

1.同源策略:只有 协议+域名+端口 一模一样才允许发AJAX请求

比如:如果你的页面不是http://baidu.com:8000,就不能向http://baidu.com:8000发起AJAX请求

2.CORS跨域:就是为AJAX请求的同源策略设置“例外规则”

怎么做?让后台加上一句响应头就可以了:

response.setHeader('Access-Control-Allow-Origin', "协议+域名+端口") //允许声明的例外站点访问我

3.总结:

跨域策略有两种——jsonp和cors

jsonp能跨域,这是因为它通过动态创建script实现的,本来就没有同源限制

cors能跨域,是在同源策略的限制下设置例外规则

jsonp不能发POST请求,因为script不能POST,而cors支持所有动词

六. 其他小知识

1.前端如何发请求?

form、a可以发请求:但是会刷新或新开页面

link、img可以发请求:但是只能以CSS、图片形式展示

script标签可以发请求:利用这点我们实现了jsonp

xhr对象可以发请求:利用这点我们实现了ajax

2.javascript的tic-toc:代码计时

console.time()
/*js代码*/
console.timeEnd()

3.readyState的五种状态

0: 未打开 → open()还没调用

1: 未发送 → send()还没调用

2: 已获取响应头和响应状态

3: 正在下载响应体

4: 请求完成

4.jQuery是怎么实现ajax的?

仔细观察jQuery实现ajax的一个实例

$.ajax({
    type: 'post',
    url: 'http://jack.com:8002/pay',
    dataType: 'json',
    success: function() {
        console.log('请求成功')
        ...
    },
    error: function() {
        console.log('请求失败')
    }
})

不难发现它就是一个函数$.ajax(),传入了一个参数,只不过这个参数是一个对象而已。

//相当于
let obj = {type: xxx, url: yyy, dataType: zzz, success: function(){}, error: function(){}}
$.ajax(obj)

若对之前讲过的原生js实现ajax的代码进行优化,封装成一句api的话。可以发现:我们需要交接的所有参数,都写在这个对象的属性之中

因此,$.ajax()这个函数,本质上就是这句优化后的api。