跨域问题和ajax

Ajax XMLHttpRequest & 跨域: 一.XMLHttpRequest: XMLHttpRequest是浏览器内置的一个构造函数 作用:基于 new 出来的 XMLHttpRequest 实例对象,可以发起 Ajax 的请求。 axios 中的 axios.get()、axios.post()、axios() 方法,都是基于 XMLHttpRequest(简称:XHR) 封装出来的! 使用 XMLHttpRequest 发起 GET 请求: 主要的 4 个实现步骤:

创建 xhr 对象

调用 xhr.open() 函数

调用 xhr.send() 函数

监听 load 事件

    <script>
        let xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://xxx.com/api/xx');
        xhr.send();
        xhr.addEventListener('load', function () {
            console.log(this.response);
        })
    </script>

请求时携带URL参数 或 提交请求体 :

URL参数,只能拼接在 URL 地址 后面 请求体,放到 send() 里面

<script>
    let xhr = new XMLHttpRequest();
    // 将请求参数拼接到url后面
    xhr.open('请求方式', 'http://www.itcbc.com/api/xx?id=1&username=zhangsan');
    xhr.send(请求体);

    xhr.addEventListener('load', function () {
        console.log(this.response);
    })
</script>

提交请求体数据,需指定Content-Type头: 当需要提交请求体数据时,需要在 xhr.open() 之后,调用 xhr.setRequestHeader() 函数,指定请求体的编码格式

    // 将请求参数拼接到url后面
    xhr.open('POST', 'http://www.itcbc.com/api/post');
    // 根据请求体格式的不同,需设置对应的Content-Type头
    xhr.setRequestHeader('Content-Type', '值')
    xhr.send('username=zs&age=20');

    xhr.addEventListener('load', function () {
        console.log(this.response);
    })
</script>

请求体格式 和 对应的Content-Type值: 为了方便服务器接收数据,当提交请求体时,需要指定一个叫做Content-Type的请求头

请求体格式Content-Type是否需要在代码中指定
参数=值&参数=值application/x-www-form-urlencoded
'{ "id": 1, "name": "zs" }'application/json
new FormData()multipart/form-data; xxxxxxxxx随机字符否,浏览器自动设置

请求体格式Content-Type是否需要在代码中指定参数=值&参数=值application/x-www-form-urlencoded是'{ "id": 1, "name": "zs" }'application/json是new FormData()multipart/form-data; xxxxxxxxx随机字符否,浏览器自动设置 例:xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded') 使用axios就不用关心这个请求头了,因为axios已经帮我们处理好了加请求头这件事,不过写原生代码,就需要自己指定了 二.数据交换格式: 数据交换格式,就是服务器端与客户端之间数据传输的格式 两种数据交换格式:

XML(很少用) JSON(主流)

什么是 JSON:

JSON(全称:JavaScript Object Notation)是一种数据交换格式,它本质上是用字符串的方式来表示对象或数组类型的数据

JSON 数据的格式有两种:对象格式 数组格式

JSON 的语法要求

属性名必须使用双引号包裹

字符串类型的值必须使用双引号包裹

JSON 中不允许使用单引号表示字符串

JSON 中不能写注释

JSON 的最外层必须是对象或数组格式(其他类型也可以,但多数是对象或数组格式)

不能使用 undefined 或函数作为 JSON 的值

对象格式的 JSON 数据,最外层使用 { } 进行包裹,内部的数据为 "key": "value" 的键值对结构:

key 必须使用英文的双引号进行包裹 value 的值只能是字符串、数字、布尔值、null、数组、对象类型(可选类型只有这 6 种)

数组格式的 JSON 数据

最外层使用 [ ] 进行包裹,内部的每一项数据之间使用英文的 , 分隔。其中: 每一项的值类型只能是字符串、数字、布尔值、null、数组、对象这 6 种类型之一。

调用浏览器内置的 JSON.parse() 函数,可以把 JSON 格式的字符串转换为 JS 数据

调用浏览器内置的 JSON.stringify() 函数,可以把 JS 数据转换为 JSON 格式的字符串

序列化和反序列化:

把真实数据转换为字符串的过程,叫做序列化 调用 JSON**.stringify()** 函数进行 JSON 的序列化

把字符串转换为真实数据的过程,叫做**反序列化 ** 调用 JSON.parse() 函数进行 JSON 的反序列化

把 XMLHttpRequest 请求到的 JSON 数据反序列化为 JS 对象: 在 xhr 对象的 load 事件中,通过 xhr.response 访问到的是 JSON 格式的字符串数据。可以调用 JSON.parse() 函数将 xhr.response 转化为 JS 对象

<script>
    let xhr = new XMLHttpRequest();
    // 将请求参数拼接到url后面
    xhr.open('请求方式', 'http://www.itcbc.com/api/xx?id=1&username=zhangsan');
    xhr.send(请求体);
    xhr.addEventListener('load', function () {
        let res = JSON.parse(this.response);//需要将xhr.response 转化为 JS 对象
        console.log(res);
    })
</script>

补充 - JSON 文件: 后缀名是 .json 的文件叫做 JSON 文件,专门用来存储 JSON 格式的数据。 注意:.json 结尾的文件,一般都是项目的配置文件 三.封装自己的 Ajax 函数: 定义ajax函数的参数选项: 自定义的 Ajax 函数,它接收一个配置对象作为参数。配置对象中包含如下 5 个参数选项:

参数选项说明
method请求的类型(GET 或 POST)
url请求的 URL 地址
data请求体数据,有三种格式,分别是(FormData 格式、JSON 格式、普通字符串格式)
success请求成功之后的回调函数

参数选项说明method请求的类型(GET 或 POST)url请求的 URL 地址data请求体数据,有三种格式,分别是(FormData 格式、JSON 格式、普通字符串格式)success请求成功之后的回调函数 实现步骤:

创建 xhr 实例对象 根据用户指定的 method 和 url 发起对应的请求 把响应的 JSON 数据转换为 JS 对象 调用 success 成功的回调,把请求的结果当作参数传递进去

注意事项:

有get post 请求分开类型写 data数据有三种类型 string object formdata 区分开 post请求 xhr.setRequestHeader设置对应的请求头的 Content-Type 类型 当data=FormData时 instanceof 的运用 实例 instanceof 构造函数

请求通用代码如下: ', data: { publisher: '黑马出版社', appkey: 'lijiahao123' }, success(result) { console.log(result); } }) function ajax({ url, type, data = '', success }) { const xhr = new XMLHttpRequest(); // 判断 请求类型 if (type === 'get') { // get请求的相关的代码 if (typeof data === 'object') { data = new URLSearchParams(data).toString(); } xhr.open(type, url + '?' + data); xhr.send(); } else if (type === 'post') { // post请求的相关的代码 xhr.open(type, url);

            // 判断是不是字符串
            if (typeof data === 'string') {
                xhr.setRequestHeader(
                    'Content-type',
                    'application/x-www-form-urlencoded'
                );
                xhr.send(data);
            } else if (typeof data === 'object') {
                // 判断是不是对象

                // 判断是不是 FormData 实例
                if (data instanceof FormData) {
                    // 是 FormData 实例
                    xhr.send(data);
                } else {
                    // 普通的对象
                    xhr.setRequestHeader('Content-type', 'application/json');
                    const str = JSON.stringify(data);
                    xhr.send(str); // 传递 a=b&c=d
                }
            }
        }
        xhr.addEventListener('load', function () {
            const obj = JSON.parse(this.response);
            success(obj);
        });
    }
</script>

四.同源策略 & 跨域: 同源: 同源指的是两个 URL 地址具有相同的协议、主机名、端口号 例如,下表给出了相对于 www.test.com/index.html 页面的 5 个同源检测结果:

URL是否同源原因说明www.test.com/other.html是同源(协议、域名、端口相同)www.test.com/about.html否协议不同(http 与 https)blog.test.com/movie.html否域名不同(www.test.com 与 blog.test.com)www.test.com:7001/home.html否端… 80 端口与 7001 端口)www.test.com:80/main.html是同… 同源策略: 同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。 浏览器的同源策略规定:不允许非同源的 URL 之间进行资源的交互。 例:

www.escook.cn/index.html 同源,接口调用成功 www.escook.cn/api/login www.escook.cn/index.html 非同源,接口调用失败 www.liulongbin.top/api/login

跨域: 同源指的是两个 URL 的协议、主机名、端口号完全一致,反之,则是跨域。 出现跨域的根本原因:浏览器的同源策略不允许非同源的 URL 之间进行资源的交互。

网页:www.test.com/index.html 接口:www.api.com/userlist 受到同源策略的限制,上面的网页请求下面的接口会失败!

浏览器允许发起跨域请求。但跨域请求回来的数据,会被浏览器拦截,无法被页面获取到 突破浏览器跨域限制的两种方案: JSONP 和 CORS 是实现跨域数据请求的两种技术方案

​ ​

方案诞生的时间方案来源优点缺点
JSONP出现较早民间(非官方)兼容性好(兼容低版本 IE)仅支持 GET 请求
CORS出现较晚W3C 官方标准支持 GET、POST、PUT、DELETE、PATCH等常见的请求方式不兼容某些低版本浏览器

方案诞生的时间方案来源优点缺点JSONP出现较早民间(非官方)兼容性好(兼容低版本 IE)仅支持 GET 请求CORS出现较晚W3C 官方标准支持 GET、POST、PUT、DELETE、PATCH等常见的请求方式不兼容某些低版本浏览器 注意:目前 JSONP 在实际开发中很少会用到,CORS 是跨域的主流技术解决方案 CORS 的两个主要优势:

CORS 是真正的 Ajax 请求,支持 GET、POST、DELETE、PUT、PATCH 等这些常见的 Ajax 请求方式 只需要后端开启 CORS 功能即可,前端的代码无须做任何改动

JSONP: JSONP 是实现跨域数据请求的一种技术解决方案。它只支持 GET 请求,不支持 POST、DELETE 等其它请求

在实际开发中很少被使用 在面试中可能会问到 JSONP 的原理

在解决跨域问题时:

CORS 方案用到了 XMLHttpRequest 对象,发起的是纯正的 Ajax 请求 JSONP 方案没有用到 XMLHttpRequest 对象,因此,JSONP 不是真正的 Ajax 技术

结论:只要用到了 XMLHttpRequest 对象,发起的就是 Ajax 请求! JSONP 的底层实现原理: JSONP 在底层,用到了 原因:

JSONP 的底层实现原理:

把非同源的 JavaScript 代码请求到本地,并执行:

     

如果请求回来的 JavaScript 代码只包含函数的调用,则需要程序员手动定义 show 方法。

 

      <script src="http: //www.itcbc.com:3006/api/getscri…">

缺点:服务器响应回来的代码中,调用的函数名是写死的

在指定 时,可以通过查询参数中的 callback,自定义回调函数的名称:

<script src="http: //www.itcbc.com:3006/api/jsonp?c…

在指定 时,还可以通过查询参数的方式,指定要发送给服务器的数据:

<script src="http: //www.itcbc.com:3006/api/jsonp?c…">

五.防抖 & 节流: 防抖: 防抖(debounce)指的是:频繁触发某个操作时,只执行最后一次 防抖的应用场景: 场景:搜索框只在输入完后,才执行查询的请求。 好处:这样可以有效减少请求的次数,节省网络资源。 核心代码: ; getData(queryStr); }, 1000); });

节流: 节流(throttle)指的是:单位时间内,频繁触发同一个操作,只会触发 1 次。 节流的应用场景: 射击游戏中,单位时间内只能发射一颗子弹。 核心代码:

    // 点击按钮的时候先判断 isLoadding true还是false
    //  true 请求在发送中  return
    //  false 没有请求
    //   先设置 isLoadding true
    //   发送请求出去
    //  请求回来了  设置 isLoadding = false

    document.querySelector('button').addEventListener('click', function () {
        if (isLoadding) {
            return;
        }
        isLoadding = true;
        // 发送请求的时候  禁用按钮
        // this.disabled=true;
        getData();
    });
    function getData(query = '') {
        console.log('请求发送出去');
        axios({
            method: 'get',
            url: 'http://www.itcbc.com:3006/api/getbooks' + query,
            // params:{},
        }).then((result) => {
            console.log('数据回来了');
            // document.querySelector('button').disabled=false
            isLoadding = false;
        });
    }
</script>