Ajax

130 阅读3分钟

1.Ajax概述

1.1 AJAX 简介

AJAX 全称为Asynchronous JavaScript And XML,就是异步的JS 和XML

通过AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据

AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式

1.2 XML 简介

XML 可扩展标记语言。

XML 被设计用来传输和存储数据。

XML 和HTML 类似,不同的是HTML 中都是预定义标签,而XML 中没有预定义标签,全都是自定义标签,用来表示一些数据。

比如说我有一个学生数据:

name = “孙悟空” ; age = 18 ; gender = “男” ;

用XML 表示:

<student>
    <name>孙悟空</name>
    <age>18</age>
    <gender></gender>
</student>

现在已经被JSON 取代了。

{"name":"孙悟空","age":18,"gender":"男"}

1.3 AJAX 的特点

优点

可以无需刷新页面而与服务器端进行通信

允许你根据用户事件来更新部分页面内容

缺点

没有浏览历史,不能回退

存在跨域问题(同源)

SEO 不友好

2. HTTP相关问题

2.1 MDN 文档

developer.mozilla.org/zh-CN/docs/…

2.2 HTTP 请求交互的基本过程

image.png

前后应用从浏览器端向服务器发送HTTP 请求(请求报文)

后台服务器接收到请求后, 调度服务器应用处理请求, 向浏览器端返回HTTP响应(响应报文)

浏览器端接收到响应, 解析显示响应体/调用监视回调

2.3 HTTP 请求报文

image.png

2.4 HTTP 响应报文

image.png

2.5 post 请求体参数格式

Content-Type: application/x-www-form-urlencoded;charset=utf-8

用于键值对参数,参数的键值用=连接, 参数之间用&连接

例如: name=%E5%B0%8F%E6%98%8E&age=12

Content-Type: application/json;charset=utf-8

用于 json 字符串参数

例如: {"name": "%E5%B0%8F%E6%98%8E", "age": 12}

Content-Type: multipart/form-data

用于文件上传请求

2.6 常见的响应状态码

200 OK 请求成功。一般用于GET 与POST 请求

201 Created 已创建。成功请求并创建了新的资源

401 Unauthorized 未授权/请求要求用户的身份认证

404 Not Found 服务器无法根据客户端的请求找到资源

500 Internal Server Error 服务器内部错误,无法完成请求

2.7 不同类型的请求及其作用

GET: 从服务器端读取数据(查)

POST: 向服务器端添加新数据 (增)

PUT: 更新服务器端已经数据 (改)

DELETE: 删除服务器端数据 (删)

3.搭建服务端

3.1 NodeJS的安装与介绍

下载网址:nodejs.cn/download/

3.2 express框架介绍与基本使用

安装插件

npm i express

新建index.js

const express = require('express')
const app = express()
app.get('/',(req,res)=>{
    res.setHeader("Access-Control-Allow-Origin", "*")
    res.send('ok')
})
app.listen(8080,()=>{
    console.log('listening 8080');
})

启动

node index.js

4.AJAX请求

4.1 发送get请求

前端代码

<button id="btn">点击发送请求</button>
 
<script>
    const btn = document.getElementById('btn')

    btn.onclick = ()=>{
        //1创建对象
        const xhr = new XMLHttpRequest()
        //2.初始化 请求类型,url,参数
        xhr.open('get','http://127.0.0.1:8080?a=100&b=200')//设置参数
        //3.发送
        xhr.send()
        //4.事件绑定
        xhr.onreadystatechange = ()=>{
            if(xhr.readyState === 4) {
                if(xhr.status>=200 && xhr.status<300){
                    document.write(xhr.response)
                }
            }
        }
    }
</script>

4.3 发送POST请求

const xhr = new XMLHttpRequest()
xhr.open('post','http://127.0.0.1:8080')
xhr.send('a=100&b=200')
xhr.onreadystatechange = ()=>{
    if(xhr.readyState === 4) {
        if(xhr.status>=200 && xhr.status<300){
            document.write(xhr.response)
        }
    }
}

4.4设置请求头信息

前端代码xhr.setRequestHeader

btn.onclick = ()=>{
    const xhr = new XMLHttpRequest()
    xhr.open('post','http://127.0.0.1:8080')
    xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
    xhr.setRequestHeader('name','xiaoming')
    xhr.send()
    xhr.onreadystatechange = ()=>{
        if(xhr.readyState === 4) {
            if(xhr.status>=200 && xhr.status<300){
                document.write(xhr.response)
            }
        }
    }
}

后端要设置响应头res.setHeader

app.all('/',(req,res)=>{
    res.setHeader("Access-Control-Allow-Origin", "*")
    res.setHeader("Access-Control-Allow-Headers", "*")
    res.send('ok')
})

4.5 服务端响应JSON数据

后端返回数据代码字符串对象

app.all('/',(req,res)=>{
    res.setHeader("Access-Control-Allow-Origin", "*")
    res.setHeader("Access-Control-Allow-Headers", "*")
    res.send(JSON.stringify({
        name:'小明'
    }))
})

方法一:手动对数据转换JSON.parse

 xhr.onreadystatechange = ()=>{
    if(xhr.readyState === 4) {
        if(xhr.status>=200 && xhr.status<300){
            let data = JSON.parse(xhr.response)
            document.write(data.name)
        }
    }
}

方法二:自动转换,设置xhr.responseType='json'

const xhr = new XMLHttpRequest()
xhr.open('post','http://127.0.0.1:8080')
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
xhr.setRequestHeader('name','xiaoming')
xhr.responseType='json'
xhr.send()
xhr.onreadystatechange = ()=>{
    if(xhr.readyState === 4) {
        if(xhr.status>=200 && xhr.status<300){
            document.write(xhr.response.name)
        }
    }
}
 
 

5.nodemon自动重启工具安装

npm i -g nodemon

nodemon ./index.js

nodemon运行 提示错误:无法加载文件 C:\Users…\AppData\Roaming\npm\nodemon.ps1,因为在此系统上禁止运行脚本

这是你机子禁止运行脚本,解决办法

1.管理员身份打开powerShell

2.输入set-ExecutionPolicy RemoteSigned

如果未成功,提示如下内容

……内容省略……

要更改当前用户的执行策略,请运行 "Set-ExecutionPolicy -Scope CurrentUser"// 这实际上是管理员运行的意思

……内容省略……

那么输入Set-ExecutionPolicy -Scope CurrentUser运行即可,之后输入RemoteSigned回车运行即可,再次执行nodemon,发现成功了

6.IE缓存问题解决

添加时间戳

 xhr.open('GET', 'http://127.0.0.1/?t=' + new Date())

7.异常处理

7.1 AJAX请求超时与网络异常处理

超时设置xhr.timeout

错误处理回调xhr.ontimeout

const xhr = new XMLHttpRequest();
xhr.timeout = 2000
xhr.ontimeout = ()=>{
    alert('error')
}
xhr.onerror = ()=>{
    alert('network error')
}
xhr.open('GET', 'http://127.0.0.1/')
xhr.send()
xhr.onreadystatechange = () => {
    if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
            document.write(xhr.response)
        }
    }
}

7.2 AJAX取消请求 xhr.abort()

<script>
    const el = document.getElementById('send')
    const el1 = document.getElementById('cancel')
    const xhr = new XMLHttpRequest();
    el.onclick = () => {
        xhr.open('GET', 'http://127.0.0.1/')
        xhr.send()
    }
    el1.onclick = () => {
        xhr.abort()
    }
</script>

7.3 AJAX请求重复发送问题

const xhr = new XMLHttpRequest();
let isSending = false
el.onclick = () => {
    if (isSending) {
        xhr.abort()
    }
    isSending = true
    xhr.open('GET', 'http://127.0.0.1/')
    xhr.send()
    xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
            isSending = false
        }
    }
}

8.发送AJAX请求方式

8.1 jQuery发送AJAX请求

get请求,返回来的数据以json格式显示

$.get('http://127.0.0.1/',{a:100,b:100},(res)=>{
    console.log(res);
},'json')

post请求,返回来的数据以json格式显示

$.post('http://127.0.0.1/',{a:100,b:100},(res)=>{
    console.log(res);
},'json')

ajax请求,通用求求,相比上面两种方式,可以配置更多的请求信息

$.ajax({
    url:'http://127.0.0.1/',
    headers:{name:'1234'},  // 请求头部信息
    data:{ 1:100,b:200},    //请求体数据
    type:'GET',
    dataType:'json',
    timeout:2000,
    success:(res)=>{
        console.log(res);
    },
    error:(err)=>{
        console.log('出错啦');
    }
})

8.2 Axios发送AJAX请求

get请求

axios.get('http://127.0.0.1/server',{
    // URL参数
    params:{
        id:234,
        vip:10
    },
    // 请求头参数
    headers:{
        name:'xiaoming',
        age:20
    }
}).then(res=>{
    console.log(res);
})

post请求,注意请求体data的位置

axios.post('http://127.0.0.1/server', {
    username: 'xiaoming'
}, {
    // URL参数
    params: {
        id: 234,
        vip: 10
    },
    // 请求头参数
    headers: {
        name: 'xiaoming',
        age: 20
    },
}).then(res => {
    console.log(res);
})

通用请求

axios({
    //    请求方法get,post
    method: 'get',
    url: 'http://127.0.0.1/server',
    //    URL参数
    params: {
        name: 'xiaoming'
    },
    // 头信息
    headers: {
        vip: 10
    },
    //    请求体参数
    data: {
        password: 123
    }
}).then(res=>{
    console.log(res);
})

8.3 使用fetch函数发送AJAX请求

fetch参考文档:developer.mozilla.org/zh-CN/docs/…

fetch('http://127.0.0.1/server?vip=10', {
    method: 'POST',
    headers: {
        name: 'xiaoming'
    },
    body: 'username=admin&password=123'
}).then(Response => {
    return Response.text()
}).then(Response => {
    console.log(Response);
})

9.跨域

9.1 jsonp

1)jsonp是什么

jsonp 是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持get请求

2)jsonp是怎么工作的

在网页有一些标签天生具有跨域能力,比如link, iframe,script,jsonp就是利用script标签的跨域能力来发送请求的

9.2 原生jsonp实践

后端返回的结果需要是一段可执行的代码

//后端返回
app.all('/server', (req, res) => {
    res.send('console.log("hello world")')
})
// 后端返回调用函数
app.all('/server', (req, res) => {
    res.send('handle("hello world")')
})

// 前端处理函数
<script>
    function handle(data) {
        console.log(data)
    }
</script>
<script src="http://127.0.0.1/server"></script>

9.3 jQuery发送jsonp请求

接口返回设置

app.all('/server', (req, res) => {
    const c = req.query.callback
    res.send(`${c}(234)`)
})

前端代码

<script>
    const a = document.getElementById('a')
    a.onclick = () =>{
        $.getJSON('http://127.0.0.1/server?callback=?',(res)=>{
            console.log(res);
        })
    }
</script>