Ajax 基础学习

Ajax 学习

  • Ajax 可以再在不刷新网页的情况下更新页面内容

  • 检测用户名能否使用就是使用了 Ajax

  • XML 和 HTML 的区别:HTML中都是预定义标签,例如 a 就是超链接标签,span 就是行内元素标签,在 XML 中没有预定义标签

  • Ajax 可以通过用户事件来更新页面部分的内容 (例如鼠标移动)

  • Ajax 的缺点,没有浏览历史,不能回退,存在跨域问题,SEO 不友好

// 原生 Ajax 请求模板
// 发送请求
const xhr = new XMLHttpRequest();
// 初始化
xhr.open('GET', 'http://127.0.0.1:8000/json-server');
xhr.send();
xhr.addEventListener('readystatechange', () => {
    if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {

        }
    }
})

HTTP 协议

  • HTTP 是一种超文本传输协议,他规定了请求和响应的部分

  • 请求报文:

    • 请求行:GET 或 POST + URL + HTTP 协议版本
    • 请求头:Host: baidu.com,Cookie: name = noobming
    • 空行:真的空了一行
    • 请求体 GET 请求体为空,POST 请求体可以不为空
  • 响应报文:

    • 响应行:协议版本 + 相应状态码 (200) + 相应状态字符串 (‘OK’)
    • 响应头: 对响应体内容进行描述
    • 空行:真的空了一行
    • 响应体:返回的结果
  • 在 google 浏览器中查看报文:打开浏览器里的 F12 开发者工具,然后到 network 选项里并且刷新页面,就可以看到一堆请求 (看不到请求的话请 F5 刷新一下)

    • Query String Parameters 是对请求行的 URL 里面的参数提取出来方便查看

安装 Nodejs 和 Express

  • 首先在工作区终端执行 npm init --yes 完成初始化
  • 再执行 npm i express 安装 express
  • 编写 express:
// 引入 express
const express = require('express');

// 创建应用对象
const app = express();

// 创建路由规则
app.get('/', (request, response) => {
    // 设置简单的响应
    response.send('hello express');
})

// 监听端口,启动服务
app.listen(8000, () => {
    console.log("服务启动,监听 8000 端口");
})
  • 在脚本目录下执行 node expressTest.js
  • 在浏览器中打开 localhost:8000 观察结果

Ajax 案例的准备

  • 不能同时启动两个服务,要先关闭掉一个服务 (关闭服务的方法:Ctrl+c)
  • 其他的和上面的是一样的,路由规则这里有一点改动
// 创建路由规则
app.get('/server', (request, response) => {
    // 设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    response.send('hello ajax');
})
  • 打开 localhost:8000/server 观察响应头和页面文字

  • readystate 属性,分别有状态 0,1,2,3,4

readystate属性解释
0未初始化
1载入 (调用 open 方法)
2载入完成
3交互 (开始接受服务器响应的数据)
4完成响应
  • readystatechange 属性是只要状态码改变就触发这个事件,但是我们需要判断 readystate == 4 的时候也就是数据已经到客户端的时候才能执行代码
  • 完整代码:
const btn = document.querySelector('button');
const result = document.querySelector('#result');
btn.addEventListener('click', () => {
    // 创建对象
    const xhr = new XMLHttpRequest();
    // 初始化
    xhr.open('GET', 'http://127.0.0.1:8000/server');
    // 发送
    xhr.send();
    // 事件绑定,处理服务端返回的结果
    xhr.addEventListener('readystatechange', () => {
        // 服务端返回了所有的结果时才执行这个事件
        if (xhr.readyState === 4) {
            // 判断响应的状态码 == 200
            if (xhr.status >= 200 && xhr.status < 300) {
                // 处理客户端响应结果
                // 相应行:
                console.log(xhr.status);// 状态码
                console.log(xhr.statusText);// 状态字符串
                console.log(xhr.getAllResponseHeaders());// 获取所有响应头
                console.log(xhr.response); // 响应体
                // 设置返回到页面的文本
                result.innerHTML = xhr.response;
            }
        }
    })
})
  • 这样我们就没有刷新页面就得到了服务端返回的值

  • 设置 Ajax 请求的参数

    • 在 URL 后面添加参数,例如:?a=10&b=20

Ajax Post 请求

  • post 请求需要修改 open 函数
xhr.open('POST', 'http:/127.0.0.1:8000/server');
  • 并且需要在服务端添加 post 方法 (和 get 方法基本一样)
app.post('/server', (request, response) => {
    // 设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置响应体
    response.send('hello ajax by POST');
})
  • post 请求传递参数是在 send 函数里添加的
xhr.send('a=100&b=200');

Ajax 设置请求头的信息

  • 在 open 方法后面添加方法
xhr.setRequestHeader('请求头名','请求头值');
  • Content-Type:设置请求体类型
  • 有些自定义请求头浏览器不允许我们发送 (例如 name)
  • 需要在服务端的 post 方法中添加这样一个自定义属性
// 表示所有类型的头信息我都可以接受
response.setHeader('Access-Control-All-Headers','*');
  • 注意:setHeader 需要放在 send 方法的前面,否则会报错
  • 这时浏览器会发一个 option 的请求来判断是否有这个权限,这时可以把 post 请求改成 all 表示接受所有类型的请求

Ajax 服务端响应 json

  • response.send() 方法只能传递字符串类型的数据,所以要对 json 格式的数据进行转换
// 数据构建
const data = {
  name: 'noobming'
};
// 转换成字符串类型
let str = JSON.stringify(data);
// 设置响应体
response.send(str);
  • html 页面获取的字符串可以手动转换成 json 格式
let data = JSON.parse(xhr.response);
  • 自动转换:设置响应体数据类型

  • 在上面设置 xhr.responseType = 'json'

nodemon 工具

  • nodemon 自动重新启动应用

Ajax 中的 IE 缓存问题

  • 当 IE 接收 Ajax 请求的时候他会将请求的数据缓存到本地,当第二次请求的时候 IE 不从服务器获取数据,而是从本地缓存获取数据 (数据未更新)
  • 这个问题在后续的 ie 版本中被解决了
  • 解决方法 在请求地址后面增加时间戳参数,这样浏览器就会认为这是两次不同的请求,这样他就会发一个新的请求而不是走本地缓存
  • 例如:
xhr.open("GET","http://127.0.0.1:8000/ie?t="+Date.now());

Ajax 网络请求超时或者网络异常的处理

  • 网络请求超过 2 秒没有回应,就取消这个请求
xhr.timeout = 2000;
  • 要在网络良好的时候设置延时多少秒可以使用 setTimeout 函数包裹延时函数
app.get('/delay', (request, response) => {
    // 设置响应头 设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    setTimeout(()=>{
        response.send('hello delay');
    },3000)
})
  • 或者也可以使用回调函数监听这个事件
// 需要提前设置
xhr.ontimeout = function() {
    alert('网络异常');
}
  • 还有网络请求失败的事件
xhr.onerror = function() {
    alert('网络错误');
}
  • 网络错误可以在 chrome 里面的开发者工具里面的 network 里面设置,可以设置正常网速,3g 网,或者掉线

Ajax 取消请求

  • 取消请求使用 abort() 函数,使用时这个请求就会被取消
  • 注意变量作用域的问题,他们两个要处在同一个对象调用的函数才能终止请求

Ajax 重复发送请求

  • 当用户点击一下就会给服务器发送一个请求,点击次数过多导致请求过多导致服务器压力过大

这个我想到了轮播图里的节流阀的原理

  • 解决方法:给本地添加一个节流阀,当第二个相同请求发送的时候就先把第一个未完成的请求给取消掉
  • 设置一个 flag 变量,当开始发送请求的时候将 flag 改为 true 当 readyState 为 4 的时候,也就是完成响应的时候把 flag 改为 false
  • 判断 flag,如果为 true 的话 (也就是正在发送请求) 时取消上一个请求 (abord),发送新请求
// 是否正在发送请求 (flag)
let isSending = false;
btns[0].onclick = function() {
    // 判断标识变量是否有正在发送请求,如果有,就取消这个请求
    if(isSending) x.abort();
    x = new XMLHttpRequest();
    isSending = true;
    x.open('GET', 'http://127.0.0.1:8000/delay');
    x.send();
    x.onreadystatechange = function() {
        if(x.readyState===4) {
            // 请求完成,修改标识变量
            isSending = false;
        }
    }
}

在 jQuery 中发送 Ajax 请求

  • 在 jQuery 中发送 Ajax 的模板
$("button").eq(0).on("click", function () {
    $.get('http://127.0.0.1:8080/jquery-server',{a:100,b:200},function(data) {
        // data 参数是响应体参数
    },'json');
    // 最后一个参数是响应体类型
})
  • 服务端和正常的是一样的

  • get 方法和 post 方法的区别,get 方法是将请求的参数贴到 url 地址的后面,而 post 请求是将参数存到请求体中

  • 第四个参数是可能返回的数据格式,假如你返回的是一个字符串格式的json (JSON.stringify()) 如果你不加最后一个参数 json 的话,他返回的就是一个普通的字符串,如果你加了最后一个参数,他返回的就是一个 json 格式的对象

  • 通用型方法 Ajax

$.ajax({
    // url
    url: "http://127.0.0.1:8000/jquery-server",
    // 参数
    data: {
        a: 10,
        b: 20
    },
    // 请求类型
    type: "GET",
    // 响应体结果
    dataType: 'json',
    // 成功的回调函数
    success: function(data) {
        console.log(data);
    },
    // 超时时间
    timeout: 2000,
    // 失败的回调函数
    error: function() {},
    // 头信息的设置
    headers: {
        a: 100,
        b: 200
        // 在使用这个的时候需要设置响应体的跨域
    }
})
  • 在相应的返回值上可以不用将 json 转换为字符串格式他也能成功返回
  • 在设置跨域请求的时候需要在服务端添加上这两个响应头:
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-All-Headers', '*');

axios 发送 Ajax 请求

  • 使用 cdn 链接引入 axios 推荐 bootCDN
  • 设置 baseURL 之后,下面的所有 url 都不用加前面相同的那一堆,直接写最后的部分就可以
// 设置 baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';
// GET 请求
axios.get("/axios-server", {
    // URL 参数
    params: {
        id: 100,
        name: "noobMisng"
    },
    // 请求头信息
    headers: {
        age: 20
    }
}).then(value => {
    // 返回结果
    console.log(value);
})
  • post 请求的时候多了一个请求体参数 data (对象格式)
  • post 请求中第二个参数作为请求体的参数传递过去,第三个数据是其他参数
axios.post("/axios-server",{
    // 请求体传递参数 (data)
    name: "noobMing",
    age: 18
},{
    // 其他参数
    params: {
        id: 100,
        name: "noobMisng"
    },
})
  • 使用 axios 方法发送 Ajax 请求

  • 代码如下:

axios({
    // 请求方法
    method: "POST",
    // url (前提设置 baseURL)
    url:"/axios-server",
    // url 参数
    params: {
        vip: 10,
        level:20
    },
    // 头信息
    headers: {
        a:100,
        b:200,
    },
    // 请求体参数
    data: {
        username:"noobMing",
        age:18
    }
}).then(response=>{
    console.log(response);
})

使用 fetch 函数发送 Ajax 请求

  • fetch 是全局对象,可以直接调用,返回一个 promise 对象
  • 要是想传递 url 参数的话就直接在 url 后面连接上
fetch('http://127.0.0.1:8000/axios-server', {
    // 请求方法
    method: "POST",
    // 请求头
    headers: {
        name: "noobMing"
    },
    // 请求体
    body: 'username=admin'
}).then(response => {
    console.log(response);
});

跨域

同源策略

  • 同源:url 和 Ajax 请求的 url 必须协议,域名,端口号必须完全相同
  • 违背同源策略就是跨域

jsonp 解决跨域

  • jsonp 是一种非官方解决跨域的方法,只支持 get 请求

  • 有一些标签天生具备跨域的能力,例如 img link iframe 和 script

  • 用 script 实现 jsonp 服务的时候必须使用 JavaScript 代码作为返回值,才能被网页接收

<!-- jsonp 服务 -->
<script src="要跨域的部分"></script>
  • 下面是原生跨域操作的实例:
// 服务端
app.all('/result', (request, response) => {
    const data = {
        name: "noobMing"
    };
    let str = JSON.stringify(data);
    response.send(`handle(${data})`);
})
<!-- 客户端 -->
<script>
    // 处理数据
    function handle(data) {
        const result = document.querySelector('#result');
        result.innerHTML = data.name;
    }
    // script 标签甚至可以自己创建而不用预先写
    const script = document.createElement('script');
    // 设置 src 属性
    script.src = 'http://127.0.0.1:8000/result';
    // 把 script 标签放入文档中
    document.body.appendChild(script);
</script>
  • 这个方法就相当于 script 向后端发送一个 get 请求,返回的是一个前端 (服务端) 预先定义好的一个函数,通过参数来把数据传递过来,前端使用这个函数来处理传过来的数据

jQuery 发送 jsonp 请求

  • 使用 jQuery 发送 jsonp 请求的时候需要添加一个 url 参数 ?callback=?
$.getJSON('url',function(data){});
  • 在 jQuery 中感觉他不用前端需要提前注册好函数,他会自动注册一个函数,存在 callback 参数里
// 获取函数
let cb = request.query.callback;
// 返回的时候可以直接这样写
response.send(`${cb}(${str})`);
// 这样返回给前端的就是一个函数,在回调函数的 data 存放的就是后端的数据

跨域请求的另一种解决方案 cors

  • cors:跨域资源共享,他是官方给出的解决方案

  • 支持 get post,不需要在客户端做改变,完全在服务端处理

  • 这个响应头表示哪些网页可以给我们发请求

  • cors 是设置一个响应头,里面会标出允许跨域的网站的域名,被设置允许的才可以跨域

response.setHeader('Access-Control-Allow-Origin', '*');
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值