学习Ajax

下面所有过程的代码链接

1 由来

以前网站开发人员如何发请求
用 form 可以发请求,但是会刷新页面或新开页面
用 a 可以发 get 请求,但是也会刷新页面或新开页面
用 img 可以发 get 请求,但是只能以图片的形式展示
用 link 可以发 get 请求,但是只能以 CSS、favicon 的形式展示
用 script 可以发 get 请求,但是只能以脚本的形式运行
有没有什么方式可以实现
get、post、put、delete 请求都行
想以什么形式展示就以什么形式展示
微软的突破
IE 5 率先在 JS 中引入 ActiveX 对象(API),使得 JS 可以直接发起 HTTP 请求。
随后 Mozilla、 Safari、 Opera 也跟进(抄袭)了,取名 XMLHttpRequest,并被纳入 W3C 规范

2 Ajax

Jesse James Garrett 将如下技术取名叫做 AJAX:异步的 JavaScript 和 XML

  1. 使用 XMLHttpRequest 发请求
  2. 服务器返回 XML 格式的字符串(前端的话,大多数为JSON)
  3. JS 解析 XML,并更新局部页面

JSON 是一种抄袭了javascript的语言
1.JSON没有抄袭function和undefined和symbol
2.JSON的字符串首位必须是" "
3.JSON有六种数据类型, number,string,boolean,object,null,array

如何使用 XMLHttpRequest 发送请求

前端代码

myButton.addEventListener('click', (e)=>{
  let request = new XMLHttpRequest()
  request.open('get', '/xxx') // 配置request
  request.send()
  request.onreadystatechange = ()=>{
    if(request.readyState === 4){
      console.log('请求响应都完毕了')
      console.log(request.status)
      if(request.status >= 200 && request.status < 300){
        console.log('说明请求成功')
        console.log(typeof request.responseText)
        console.log(request.responseText)
        let string = request.responseText
        // 把符合 JSON 语法的字符串
        // 转换成 JS 对应的值
        let object = window.JSON.parse(string) 
        // JSON.parse 是浏览器提供的
        console.log(typeof object)
        console.log(object)
        console.log('object.note')
        console.log(object.note)

      }else if(request.status >= 400){
        console.log('说明请求失败') 
      }

    }
  }
})

后端代码

  }else if(path==='/xxx'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/json;charset=utf-8')
    response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8001')
    response.write(`
    {
      "note":{
        "to": "小谷",
        "from": "方方",
        "heading": "打招呼",
        "content": "hi"
      }
    }
    `)
    response.end()

同源策略

当我们用request.open('get','https://www.baidu.com)发送请求,会出现这种情况

image.png

image.png

请求成功,但是response却收不到


image.png

,

  1. http://baidu.com 可以向 http://www.baidu.com 发 AJAX 请求吗 no
  2. http://baidu.com:80 可以向 http://baidu.com:81 发 AJAX 请求吗 no
    这是因为ajax不允许发送不同源的请求,而form,img,script等上面提到的请求方式可以向其他域名请求是因为他们只能发送请求而不能收到响应内容。
    浏览器必须保证
    只有 协议+端口+域名 一模一样才允许发 AJAX 请求
    那怎么才可以发送Ajax请求到其他的网站呢?
    CORS
    CORS可以告诉浏览器,我俩一家的,别阻止他
    突破同源策略 === 跨域

Cross-Origin Resource Sharing
C O源 R S

CORS 跨域

现在我们用两个网站 frank.com:8001和jack.com:8002同时向向jack.com:8002/xxx(即jack的后台)发送Ajax请求
jack.com

jack.com

jack.com

image.png

frank.com:8001 访问jack.com:8002/xxx
frank.com
image.png

但响应失败
image.png

这时我们只要在访问的服务器添加一句

response.setHeader('Access-Control-Allow-Orgin','http://frank.com:8001')
image.png

然后就可以访问成功


image.png

如果需要多个域名跨源

response.setHeader('xxxx','*');

如果是指定几个进行跨源分享
Enable Access-Control-Allow-Origin for multiple domains in nodejs [duplicate]

3 实现相对完整的Ajax

首先了解一下http请求和响应格式
HTTP请求的格式

1 动词 路径 协议/版本
2 Key1: value1
2 Key2: value2
2 Key3: value3
2 Content-Type: application/x-www-form-urlencoded
2 Host: www.baidu.com
2 User-Agent: curl/7.54.0
3
4 要上传的数据

说明

请求最多包含四部分,最少包含三部分。(也就是说第四部分可以为空)
第三部分永远都是一个回车(\n)
动词有 GET POST PUT PATCH DELETE HEAD OPTIONS 等
这里的路径包括「查询参数」,但不包括「锚点」
如果你没有写路径,那么路径默认为 /
第 2 部分中的 Content-Type 标注了第 4 部分的格式

HTTP响应的格式

1 协议/版本号 状态码 状态解释
2 Key1: value1
2 Key2: value2
2 Content-Length: 17931
2 Content-Type: text/html
3
4 要下载的内容

状态码的种类

1xx 不常用
2xx 表示成功
3xx 表示滚吧
4xx 表示你丫错了
5xx 表示好吧,我错了
状态解释没什么用
第 2 部分中的 Content-Type 标注了第 4 部分的格式
第 2 部分中的 Content-Type 遵循 MIME 规范

根据上面请求响应格式,我们来一步一步实现Ajax(分为四步)

  1. 声明并定义XMLHttpRequest对象
let request=new XMLHttpRequest()
  1. 配置request
    请求格式的第一部分
request.open('get','/xxx')  //get请求,路径为/xxx

请求格式的第二部分

request.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
  1. 判断请求完成还有请求是否成功
    请求所处状态
request.readyState  // 4

响应格式的第一部分

request.status   // 200
request.statusText  //OK

响应格式的第二部分

request.getAllResponseHeaders()
request.getResponseHeader('Content-Type')

响应格式的第四部分

request.responseText
  1. 发送request
    请求格式的第四部分
request.send('请求体‘)//第四部分可以为空 ,可以不传值

封装Ajax

window.jQuery=function(nodeOrSelector){
    let nodes={};
    nodes.addClass=function () {

    }
    nodes.html=function () {

    }
    return nodes;
}

window.jQuery.ajax = function (url, method, body, successFn, failFn) {

    let xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                successFn.call(undefined,xhr.responseText);
            } else if (xhr.status >= 400) {
                failFn.call(undefined,xhr);
            }
        }
    }


    xhr.send(body);

}


btn.addEventListener('click', (e) => {
    window.jQuery.ajax(
        '/xxx',
        'post',
        'a=1&b=2',
        (responseText)=>{ console.log(1)},
        (xhr)=>{console.log(2)}
    )
})

Promise封装Ajax

window.jQuery=function(nodeOrSelector){
    let nodes={};
    nodes.addClass=function () {

    }
    nodes.html=function () {

    }
    return nodes;


}

window.jQuery.ajax = function ({url,method,body,headers}) {


    return new Promise(function (resolve,reject) {
        let xhr = new XMLHttpRequest();
        xhr.open(method, url);
        for(let key in headers){
            let value=headers[key];
            xhr.setRequestHeader(key,value);
        }
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    resolve.call(undefined,xhr.responseText);
                } else if (xhr.status >= 400) {
                    reject.call(undefined,xhr);
                }
            }
        }
        xhr.send(body);
    })


}




btn.addEventListener('click', (e) => {
    let obj={
        'url':'/xxx',
        'method':'post',
        'body':'a=1&b=2',
        'headers':{
            'Content-Type':'application/x-www-form-urlencoded',
            'name':'frank'
        }


    }
    window.jQuery.ajax(obj)
        .then(
            (responseText)=>{
        console.log(responseText);},
            (request)=>{
        console.log(request)}
        )
})

4 总结

你才返回对象,你全家都返回对象(Ajax只是返回字符串,只不过字符串刚好符合json对象的语法,后台无法返回对象)
JS 是一门语言,JSON 是另一门语言,JSON 这门语言抄袭了 JS这门语言
AJAX 就是用 JS 发请求
响应的第四部分是字符串,可以用 JSON 语法表示一个对象,也可以用 JSON 语法表示一个数组,还可以用 XML 语法,还可以用 HTML 语法,还可以用 CSS 语法,还可以用 JS 语法,还可以用我自创的语法

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

推荐阅读更多精彩内容