web前后端交互—重学Ajax

Ajax

Ajax 即“Asyn Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式、快速动态网页应用的网页开发技术,无需重新加载整个网页的情况下,能够更新部分网页的技术。

通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新,所以也被称之为 局部刷新的更新技术

猫眼电影接口文档:
i.maoyan.com/api/mmdb/mo…


Ajax基础

整体流程

一. 创建一个XMLHttpRequest对象

二. 调用(有三个参数)

  1. 请求方式
  • get(会把你提交的的东西都暴露在地址上)
  • post不会,它放在请求体里,所以更安全一点
  1. 请求地址(文件在哪)
  2. 传布尔值(是否异步,true是异步,false为同步)

三. 发出去

四. 监听readyState值(或者直接用onload)

  • 监听完readyState值,继续监听状态码
<script>
    //一. 创建一个XMLHttpRequest对象
    var xhr=new XMLHttpRequest()
    // 二. 调用(有三个参数)
    // 1. 请求方式
    // 2. 请求地址(文件在哪)
    // 3. 传布尔值(是否异步,true是异步,false为同步)
    xhr.open("get","./1.json",true)

    // 三. 发出去
    xhr.send()
</script>

我们可以认为,此时已经跟后端联系上了,并且把数据拿回来了,只不过是 调试工具拿到了我们还没有拿到
web前后端交互—重学Ajax

所以再进行监听

    //监听
    xhr.onreadystatechange=function(){
        console.log('电话接通')
    }

为什么是三次?
web前后端交互—重学Ajax
因为👇:
web前后端交互—重学Ajax
也就是说👇:

其实这个监听,监听的是readyState的改变,只有等于4时,可以拿到成功结果

所以,我们现在监听readyState的改变

    xhr.onreadystatechange=function(){
        if(xhr.readyState===4){
            console.log(xhr.responseText)
        }
    }

成功拿到
web前后端交互—重学Ajax

但是你并不确定你上面有没有出错,(比如第二步请求的时候),所以我们再判断一下状态码

(如果正确在二百到三百之间,就解析转一下格式;不然就返回错误)

web前后端交互—重学Ajax

 xhr.onreadystatechange=function(){
        if(xhr.readyState===4){
            if(xhr.status===200){
                // 返回的是json字符串格式
                console.log(JSON.parse(xhr.responseText))
            }else{
                console.log("error",xhr.responseText)
            }
        }
    }

web前后端交互—重学Ajax


比如我们渲染一个页面👇

 <button id="btn">aaa</button>
    <ul id="list">
    </ul>
</body>


<script>
    var obtn=document.querySelector("#btn")
    var olist=document.querySelector("#list")

//——————————按钮里发请求
    obtn.onclick=function(){
       //创建一个XMLHttpRequest对象
       var xhr=new XMLHttpRequest()
      // 调用(有三个参数)
       xhr.open("get","./1.json",true)
       // 发出去
       xhr.send()
       // 监听
       xhr.onload=function(){
           if(/^2\d{2}$/.test(xhr.status)){
                  // 返回的是json字符串格式
                 //console.log(JSON.parse(xhr.responseText))
                 //调用渲染页面
                render(JSON.parse(xhr.responseText))
            }else{
                console.log("error",xhr.responseText)
            }
        }
//————————————————
    // 渲染函数
    function render(res){
        var newlist = res.data.list.map(function(item){
            return `<li>
                   <img src="${item.imgeUrl}"/>
                   <div>${item.name}</div>
                </li>`
        })
        //数组转成字符串会用逗号隔开,所以我们需要把逗号去掉
        olist.innerHTML=newlist.join("")
       }

    }
</script>

Ajax请求方式

web前后端交互—重学Ajax

json-server

// 1.json
{
    "list":[],
    "users":[],
    "shopcar":[],
    "detail":{
        "name":"手机"
    }
}

web前后端交互—重学Ajax
web前后端交互—重学Ajax

GET

比如
xhr.open("get","地址/users?id=1",true)

POST

POST在send里发送,也就是在send里写

POST两种发送格式👇

form编码—— name=kerwin&age=18
json—— {name:"kerwin",age=100}

————————————————————————————————

但是后端并不知道你传来的到底是form还是json,所以在使用post发请求时,需要在send前加一句

如果是form编码,就写👇
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")

xhr.send(`name=tiechui&age=18`)

如果是json,就写👇
xhr.setRequestHeader("content-type","application/json")

//对一个json对象,转成json字符串
xhr.send(JSON.stringify({
     name:"winter"
     age:90
}))

PUT(全部覆盖式更新)

必须先在地址里说明更新的是哪个数据(把/id写后面)

同时它也支持form和json方法,所以send前面那句也要写

然后在send里写,但是注意这个PUT是全量更新

PATCH(部分更新,补丁式)

必须先在地址里说明更新的是哪个数据(把/id写后面)

同时它也支持form和json方法,所以send前面那句也要写

然后在send里写,可以只写需要更新的

delete

只需要在地址处告诉它要删的是哪个,把/id传过去

fetch基础

基于promise实现

为了取代 XHR 的一种方式,还是属于Ajax的实现方式之一

GET

fetch默认就是get请求

fetch("http://localhost:3000/users")
这个返回的是一个promise对象

后面接两个.then()

这个.then里面可以指定一个回调函数,可以调用原型prototype上的两个方法(.json和.text,下面用.json举例)

第一个.then,需要调用.json,把我们的东西转换成json的数据

然后return出去,在后面就能拿到了

————————————
第二个.then,拿到的就是前面.then的返回值

其实就是.then的链式调用,后面.then拿到前面.then的返回值

完整就是

// .json
        fetch("http://localhost:3000/users")
        .then(res=>res.json())
        .then(res=>{
            console.log(res)
        })
       
// .text
        fetch("http://localhost:3000/users")
        .then(res=>res.text())
        .then(res=>{
            console.log(JSON.parse(res))
        })

get传参直接放在地址上?传就行

POST

<body>
    <button id="btn">aaa</button>
</body>
<script>
    var obtn=document.querySelector("#btn")


    obtn.onclick=function(){
        fetch("http://localhost:3000/users",{
            method:"POST",
            headers:{
                "content-type":"application/x-www-form-urlencoded"
            },
            body:"name=tiechui&age=18"
        })
        .then(res=>res.json())
        .then(res=>{
            console.log(res)
        })
    }
</script>

PUT、PATCH、DELETE

同理

fetch错误处理方案

        fetch("http://localhost:3000/users")
        .then(res=>{
            if(res.ok){
                return res.json()
            }else{
                //console.log(res)
                return Promise.reject({
                    status:res.status,
                    statusText:res.statusText
                })
            }
        })
        .then(res=>{
            console.log(res)
        }).catch(err=>{
            console.log("err",err)
        })

async和await 与fetch异步的结合,可以让上面的异步代码类似于同步(看起来像——执行完这个,才能下一步)

异步代码写起来像同步一样,异步编程的最高境界


axios基础

axios – npm (npmjs.com)

axios是一个基于promise的HTTP库,可以用在浏览器和node.js中

//引入
// 写在最上面,里面什么也不写
<script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>

GET

<body>
    <button id="btn">aaa</button>
</body>
<script>
    var obtn=document.querySelector("#btn")


    obtn.onclick=function(){
        // get传参方式
        //1. 直接地址?后面写
        //2. 如果要传对象,可以用params(它最后还是帮你组装进地址里)
        axios.get("http://localhost:3000/users",{
            params:{
                name:"kerwin"
            }
        })
        .then(res=>{
            console.log(res.data)
        })
        .catch(err=>{
            console.log("err",err)
        })
    }
</script>

POST

json字符串格式

    obtn.onclick=function(){
        axios.post("http://localhost:3000/users",{
            name:"kerwin",
            age:18
        })
        .then(res=>{
            console.log(res.data)
        })
        .catch(err=>{
            console.log("err",err)
        })
    }

form

 obtn.onclick=function(){
        axios.post("http://localhost:3000/users","name=tiechui&age=80")
        .then(res=>{
            console.log(res.data)
        })
        .catch(err=>{
            console.log("err",err)
        })
    }

这样可以把json对象转成form格式👇

const params = new URLSearchParams({name:"phy",age:18});  
 
 axios.post("http://localhost:3000/users",params)

……PUT、PATCH、DELETE

完整版axios配置写法

obtn.onclick=function(){
            axios({
                method:'POST',
                url:'http://localhost:3000/shopcar',
                //get params
                //put post data
                data:{
                    name:'phy',
                    age:18
                }
        }).then(res=>{
            console.log(res.data)
        }).catch(err=>{
            console.log("err",err)
        })
    }

axios拦截器(config)

请求拦截器request(前置)

响应拦截器response(后置)

两者结合loading使用

web前后端交互—重学Ajax

<script>
    var obtn = document.querySelector("#btn")

    //放外面,对整个页面生效
    // !!! 请求拦截器
    axios.interceptors.request.use(function (config) {
        //在请求被发出之前做一些事情
        console.log("loading框显示....")
        return config;
    }, function (error) {
        return Promise.reject(error);
    });

    // !!! 响应拦截器
    axios.interceptors.response.use(function (response) {
        console.log("成功隐藏loading...")
        return response;
        //也可以往里面放一些自己写的
        // return {
        //     ...response,
        //     myname:'kerwin'
        // }
    }, function (error) {
        console.log("失败隐藏loading...")
        return Promise.reject(error);
    });


    obtn.onclick = function () {
        axios.get("http://localhost:3000/users", {
            params: {
                name: "phy"
            }
        })
            .then(res => {
                console.log(res.data)
            })
            .catch(err => {
                console.log("err", err)
            })
    }
</script>

效果👇
web前后端交互—重学Ajax

axios中断器

性能方面考虑

如果你点一个a,然后又快速点b;这个时候a还没回来,然后我们把它的请求停掉,继续请求b

web前后端交互—重学Ajax

语法👇

const controller = new AbortController();

axios.get('/foo/bar', {
   signal: controller.signal
}).then(function(response) {
   //...
});
// cancel the request
controller.abort()

具体使用👇

    <button id="btn">点一下</button>
    <button id="abort">abort</button>
    
    

 const controller = new AbortController();
    obtn.onclick = function () {
        axios.get("http://localhost:3000/users", {
            signal: controller.signal
        })
            .then(res => {
                console.log(res.data)
            })
            .catch(err => {
                console.log("err", err)
            })
    }
    //终止
    oabort.onclick=function(){
        controller.abort()
    }

同源策略

一般URL有三部分组成:协议http、域名(指向主机)www、端口号,只有这三个完全相同的URL才能称之为同源。

——是一种保护策略

http://默认端口号是80

  • 不符合的话
  1. 无法读取非同源网页的Cookie、LocalStorage
  2. 无法接触非同源网页的DOM
  3. 无法向非同源地址发送ajax请求(可以发送,但浏览器会拒绝接收响应)

只要不符合同源策略,我们就称之为 “跨域访问” ,浏览器一般是不允许的,下面会讲解决方法👇

解决跨域—jsonp

jsonp(JSON with Padding) 是json一种“使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据

  • 它本身是js
  • 缺点:jsonp只能做get请求

为什么script能解决跨域问题

  1. 因为script标签本身是没有跨域限制的
  2. 需要后端配合,返回的是函数小括号()调用的格式
  3. 前端提前声明好这个函数
//1. 动态创建一个script标签
//2. 让src指向接口
//3. 然后再将它插到页面中
//4. 配合函数使用

//....
    <script>
        function test(){
            console.log("111",data)
        }

        
        var oscript=document.createElement("script")
        oscript.src="1.txt"
        document.body.appendChild(oscript)
    </script>
    
    
// 1.txt 中  
    test(“kerwin”)

为了避免前后端对接的函数名写的不一样,后端会允许前端在这个jsonp接口的后面传一个参数

这个参数就是前端提前声明好的这个函数名

web前后端交互—重学Ajax

百度搜索案例

web前后端交互—重学Ajax

百度搜索的一个jsonp接口

jsonp接口

在wd这里传入你想搜索的字符(wd在src这个api链接里)
wd=${osearch.value}

这样就可以拿到与输入内容相关的数据了
web前后端交互—重学Ajax

这时你会发现,随着你jsonp的创建,你的script标签会越创越多(所以我们过河拆桥,把它移除掉👇)

 // 等下载完执行了,就把这个标签移除掉
 // 因为script标签已经加载到内存中运行了,所以即使删了,代码也能正常运行
 oscript.onload = function(){
       oscript.remove()
 }

完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text" name="" id="search">
    <ul id="list">

    </ul>
    <script>
        var osearch = document.querySelector('#search')
        var olist = document.querySelector('#list')

        osearch.oninput = function () {
            // 拿取输入框值
            console.log(osearch.value)
            //避免输入框为空时报错,如果是空,就返回,不查了
            if(osearch.value===""){
                olist.innerHTML=""
                return
            }

            var oscript = document.createElement("script")
            oscript.src = `https://www.baidu.com/sugrec?pre=1&p=3&ie=utf-8&json=1&prod=pc&from=pc_web&sugsid=40171,39661,40206,40212,40216,40224,40274,40294,40291,40287,40285,40317,40080,40364,40351,40373,40367,40406&wd=${osearch.value}&his=%5B%7B%22time%22%3A1705912173%2C%22kw%22%3A%22%E6%88%AA%E5%9B%BE%E5%BF%AB%E6%8D%B7%E9%94%AE%22%7D%2C%7B%22time%22%3A1705947520%2C%22kw%22%3A%22%E7%BF%BB%E8%AF%91%22%2C%22fq%22%3A2%7D%2C%7B%22time%22%3A1706083906%2C%22kw%22%3A%22%E4%B8%80%E4%B8%AA%E5%90%AB%E6%9C%89%E5%A4%A7%E9%87%8F%E8%8B%B1%E6%96%87%E5%8D%95%E8%AF%8D%E7%9A%84csv%E6%96%87%E4%BB%B6%22%7D%2C%7B%22time%22%3A1706407752%2C%22kw%22%3A%22%E4%BC%98%E9%85%B7%22%2C%22fq%22%3A2%7D%2C%7B%22time%22%3A1706526327%2C%22kw%22%3A%22%E7%A8%80%E5%9C%9F%E6%8E%98%E9%87%91%E6%80%8E%E4%B9%88%E5%88%9B%E5%BB%BA%E4%B8%93%E6%A0%8F%22%7D%2C%7B%22time%22%3A1707051724%2C%22kw%22%3A%22octave%E7%9A%84disp%22%7D%2C%7B%22time%22%3A1707137166%2C%22kw%22%3A%22%E7%99%BE%E5%BA%A6%E7%83%AD%E6%90%9C%22%2C%22fq%22%3A3%7D%2C%7B%22time%22%3A1707137327%2C%22kw%22%3A%22%E6%9D%83%E9%87%8D%E7%9F%A9%E9%98%B5%E7%AC%A6%E5%8F%B7%22%7D%2C%7B%22time%22%3A1709272959%2C%22kw%22%3A%22%E6%89%87%E8%B4%9D%E8%8B%B1%E8%AF%AD%E7%BD%91%E9%A1%B5%E7%89%88%22%7D%2C%7B%22time%22%3A1709702586%2C%22kw%22%3A%22%E5%A4%A7%E9%BA%A6%22%7D%5D&req=2&csor=1&cb=test&_=1710147004051`
            document.body.appendChild(oscript)

            // 等下载完执行了,就把这个标签移除掉
            oscript.onload = function(){
                oscript.remove()
            }
        }
        // 前端提前预留好的test
        function test(data){
            //console.log(data.g)
            //.g就是这个数组
            olist.innerHTML=data.g.map(item=>
                `
                <li>${item.q}</li>
                `
            ).join("")
        }
    </script>
</body>

</html>

其他

2. 通过响应头解决跨域

web前后端交互—重学Ajax

响应头 中有这个——意思是允许所有的域通过(这个是后端设置的)
web前后端交互—重学Ajax

虽然这样看的话前端是可以直接跨域使用的

web前后端交互—重学Ajax

但是如果后端的 请求头 里设置了字段,就不能直接跨域使用了,必须前端在axios里的 headers 里传上这个字段(不同网站可能需要传的不一样)

像这样👇

web前后端交互—重学Ajax

3. 通过“反向代理方案”解决跨域

使用

nginx 反向代理服务器(在英文目录下解压)

原文链接:https://juejin.cn/post/7345356537982418978 作者:phy_winter

(0)
上一篇 2024年3月13日 上午11:03
下一篇 2024年3月13日 上午11:14

相关推荐

发表回复

登录后才能评论