Ajax&axios、fetch与跨域请求

Ajax

一、初始Ajax

1.Ajax是什么

Ajax是Asychronous Javascript and XML(异步JavaScript的XML)的缩写。
Ajax中的异步:可以异步的向服务器发送请求,在等待响应的过程中,不会阻塞当前页面,浏览器可以做自己的事情,知道成功获取响应后,浏览器才开始处理响应数据。
XML(可扩展标记语言):是前后端数据通信时传输数据的一种格式;XML现在已经不怎么用了,现在比较常用的是JSON。
Ajax其实就是浏览器与服务器之间的一种异步通信方式;使用Ajax可以在不重新加载整个页面的情况下,对页面的某部分进行更新。
例:(1)网页手机号注册检测;(2)搜索提示。

2.搭建Ajax的开发环境

Ajax需要服务器环境,非服务器环境下,很多浏览器无法正常使用Ajax。

二、Ajax的基本用法

1.XMLHttpRequest

Ajax想要实现浏览器与服务器之间的异步通信,需要依靠XMLHttpRequest,它是一个构造函数。

2.Ajax的使用步骤

(1)创建xhr对象

const xhr  = new XMLHttpRequest();

(2)监听事件,处理响应
当获取到响应后,会触发xhr对象的额readystatechange事件,可以在该事件中对响应进行处理。

xhr.onreadystatechange=()=>{
    if(xhr.readyState!=4) return;
    //获取到响应后,响应的内容会自动填充xhr对象的属性。
    //xhr.status:HTTP状态码
    //xhr.statusText:HTTP状态码说明
    if((xhr.status>=200&xhr.status<300)||(xhr.status===304)){
    //console.log('正常使用响应数据');
    console.log('xhr.responseText)}
  };

注:readystatechange事件监听readystate这个状态的变化,它的值从0-4,一共5个状态。
0:未初始化,尚未调用open();
1:启动,已经调用open(),但尚未调用send();
2:发送,已经调用send(),但尚未接收到响应;
3:接收,已经接收到部分部分数据响应;
4:完成,已经接收到全部响应数据,而且已经可以在浏览器中使用了。

readystatechange事件也可以配合addEventListener使用,不过要注意,IE6-8不支持addEventListener;为了兼容性,readystatechange中不使用this,而是直接用xhr。

(3)准备发送请求

xhr.open('HTTP方法GET、POST、PUT、DELETE''地址URL'true)//调用open并不会真正发送请求,而只是做好发送请求前的准备工作。

(4)发送请求:调用send()正式发送请求

xhr.send(null);

注:send()的参数是通过请求体携带的数据。

3.使用Ajax完成前后端通信

 const url = 'https://www.imooc.com/api/http/search/suggest?words=js'
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange=()=>{
        if(xhr.readyState!=4) return;
        if((xhr.status>=200&xhr.status<300)||(xhr.status===304)){
            console.log(xhr.responseText);
        }
    };
    xhr.open('GET',url,true);
    xhr.send(null)

三、GET请求

1.携带数据

GET请求不能通过请求体携带数据,但可以通过请求头携带。

2.数据编码

如果携带的数据是非英文字母的话,比如说汉字,就需要编码之后再传给后端,不然会造成乱码问题。可以使用encodeURIComponent()编码。

四、POST请求

1.携带数据

POST请求主要通过请求体携带数据,同时也可以通过请求头携带。如果想发送数据,直接写在send()的参数位置,一般是字符串;不能传递对象,需要先将对象转换成字符串的格式。

2.数据编码

xhr.send('username=${encodeURIComponent('张三')}&age=18');

Ajax总结:

第一步:创建xhr对象
在这里插入图片描述
第二步:
在这里插入图片描述
在这里插入图片描述
第三步:在这里插入图片描述
第四步:
在这里插入图片描述

GET和POST的注意事项:
在这里插入图片描述
在这里插入图片描述

JSON

一、初识JSON

1.JSON是什么

JSON全称:Javescript Object Notation。JSON是Ajax发送和接收数据的一种格式,和XML等类似。
例:

{"code":200,"data":[{"word":"jsp"},{"word":"js"},{"word":"json"},{"word":"js \u5165\u95e8"},{"word":"jstl"}]}

2.为什么需要JSON

JSON有三种形式,每种形式的写法都和JS中的数据类型很像,可以很轻松的和JS中的数据类型互相转换。
JS—>JSON—>PHP/JAVA
PHP/JAVA—>JSON—>JS

二、JSON 的 3 种形式

1.简单值形式 .json

JSON的简单值形式就对应着JS中的基础数据类型:数字、字符串、布尔值、null。
注:(1)JSON中没有undefined值;
(2)JSON中的字符串必须使用双引号;
(3)JSON中是不能注释的。

2.对象形式

JSON的对象形式就对应着JS中的对象。
注:(1)JSON中对象的属性名必须用双引号,属性值如果是字符串,也必须用双引号;
(2)JSON中只要涉及到字符串,就必须使用双引号;
(3)不支持undefined。

3.数组形式

JSON的数组形式就对应着JS中的数组。
注意同上。

三、JSON的常用方法

1.JSON.parse()

JSON.parse(),可以将JSON格式的字符串解析成JS中的对应值;一定要是合法的字符串,不然会报错。

console.log(JSON.parse(xhr.responseText));

2.JSON.stringify()

JSON.stringify(),可以将JS的基本数据类型、对象或者数组转换成JSON格式的字符串;一定要是合法的字符串,不然会报错。

console.log(JSON.stringify({
        username:'alex',
        age:18
    }));

3.使用JSON.parse()和JSON.stringify()封装localStorage

创建storge.js文件:

const storage = window.localStorage;
//设置
const set=(key,value)=>{
    storage.setItem(key,JSON.stringify(value))
}
//获取
const get=key=>{
    return JSON.parse(storage.getItem(key));
}
//删除
const remove=(key)=>{
    storage,removeItem(key);
}
//清空
const clear=()=>{
    storage.clear();
}
export {set,get,remove,clear};

跨域

一、初识跨域

1.跨域是什么

向一个域发送请求,如果要请求的域䄦当前域为不同域,就叫跨域;不同域之间的请求,就是跨域请求;一般跨域请求会被浏览器阻止。

2.什么是不同域,什么是同域

https(协议)://www.baidu.com(域名):443(端口号)/list(路径)

注:协议、域名、端口号,任何一个不一样,就是不同域;与路径无关,路径一不一样无所谓。

3.跨域请求为什么会被阻止

阻止跨域请求,其实是浏览器本身的一种安全策略–同源策略。
其他客户端或服务器都不存在跨域被阻止的问题。

4.跨域解决方案

(1)CORS跨域资源共享
(2)JSONP
优先使用CORS跨域资源共享,如果浏览器不支持CORS的话,再使用JSONP。

二、CORS跨域资源共享

1.CORS是什么

Access-Control-Allow-Origin:* 表明允许所有的域名来跨域请求它,*是通配符,没有任何限制。
Access-Control-Allow-Origin:http://127.0.0.1:5500 只允许指定域名的跨域请求。

2.使用CORS跨域的过程

(1)浏览器发送跨域请求;
(2)后端在响应头中添加Access-Control-Allow-Origin头信息;
(3)浏览器接收到响应;
(4)如果是同域下的请求,浏览器不会额外做什么,这次前后端通信就圆满完成了;
(5)如果是跨域请求,浏览器会从响应头中查找是否允许跨域访问;
(6)如果允许跨域,通信圆满完成;
(7)如果没找到或不包含想要跨域的域名,就丢弃响应结果。

3.CORS的兼容性

IE10及以上的版本浏览器可以正常使用CORS

三、JSONP

1.JSONP的原理

script标签跨域不会被浏览器阻止,JSONP主要就是利用script标签,加载跨域文件。

2.使用JSONP实现跨域

(1)服务器要准备好JSONP接口;
(2)手动加载JSONP接口或动态加载JSONP接口;

XHR

一、XHR的属性

1.responseType和response属性

responseType(文本形式的响应内容):responseType只能在没有设置responseType或者responseType=‘’或‘text’的时候才能使用。

2.timeout属性

timeout属性是用来设置请求的超过时间(单位ms)。
IE6-7不支持,从IE8就开始支持。

3.withCredentials属性

指定使用Ajax发送请求时是否携带Cookie;默认情况下,使用Ajax发送请求,同域会携带,而跨域时,不会携带。如果要在跨域携带,则使用withCredentials.

xhr.withCredentials = true;

最终能否成功跨域携带Cookie,还要看服务器同不同意。
从IE10开始支持。

二、XHR的方法

1.abort()

终止当前请求,一般配合abort事件一起使用。

2.setRequestHeader()

可以设置请求头信息。

xhr.setRequestHeader(头部字段的名称,头部字段的值)

请求头中的Content-Type字段用来告诉服务器,浏览器发送的数据是什么格式的。
例:

xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send('username=alex&age=18');

三、XHR的事件

1.load事件

响应数据可用时触发,代替readystatechange。

2.error事件

请求发生错误时触发。

3.abort事件

调用abort()终止请求时触发。

Ajax进阶

一、FormData

1.使用Ajax提交表单

2.FormDate的基本用法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form id="login" action="https://www.imooc.com/api/http/search/suggest?words=js" method="POST" enctype="application/x-www-form-urlencoded">
    <input type="text" name="username" placeholder="用户名">
    <input type="password" name="password" placeholder="密码">
    <input type="submit" value="登录" id="submit">
    </form>
    <script>
        //1.使用Ajax提交表单
        //2.FormData的基本用法:通过HTML的表单元素创建FormData对象
        // const fd = newFormData(login);
        //xhr.send(fd);
        const login  = document.getElementById('login');
        const {username,password} = login;
        const btn = document.getElementById('submit')
        const url = https://www.imooc.com/api/http/search/suggest?words=js;
        btn.addEventListener('click',e=>{
            //阻止表单自动提交
            e.preventDefault();
            //表单数据验证

            //发送Ajax请求
            const xhr = new XMLHttpRequest();
            xhr.addEventListener('load',()=>{
                if(xhr.status>=200&&xhr.status<300||xhr.status===304){
                    console.log(xhr.response);
                }
            },false)
            xhr.open('POST',url,true)
            //组装数据
            // const data = 'username=${username.value}&password=${password.value}'
            const data = newFormData(login);
            //FormData可用于发送表单数据
            for(const item of data){
                console.log(item);
            }
            
            xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
            xhr.send(data)
        },false)
    </script>
</body>
</html>

3.封装Ajax

1.Ajax类:ajax.js

//常量
import { HTTT_GET,CONTENT_TYPE_FORM_URLENCODED,CONTENT_JSON } from "./constants";
//工具函数
import { serialize,addURLData,serializeJSON } from './utils';
//默认参数
import DEFAULTS from './defaults';
//Ajax类
class Ajax{
    constructor(url,options){
        this.url = url;
        this.options = Object.assign({},DEFAULTS,options);
        //初始化
        this.init();
    }
    //初始化
    init(){
        const xhr = new XMLHttpRequest();
        this.xhr = xhr;
        //绑定响应事件处理程序
        this.bindEvents();
        xhr.open(this.options.method,this.url+this.addParam(),true);
        //设置responseType
       this.setResponseType();
       //设置跨域是否携带Cookie 
       this.setCookie(); 
       //设置超时
       this.setTimeout();
       //发送请求
       this.sendData();
    }
    //绑定响应事件处理程序
    bindEvents(){ 
        const xhr = this.xhr;
        const {success,httpCodeError,error,abort,timeout}=this.optiopns;
        //load
        xhr.addEventListener('load',()=>{
        if(this.ok()){
            success(xhr.response,xhr);
        }else{
            httpCodeError(xhr.status,xhr);
        }
    },false
    );
     //error
     //当请求遇到错误时,触发error事件
     xhr.addEventListener('error',()=>{
        error(xhr);
    },false
    );
    //abort
    xhr.addEventListener('abort',()=>{
        abort(xhr);
    },false
    );
    //timeout
    xhr.addEventListener('timeout',()=>{
        timeout(xhr);
    },false
    );
};

//检测相应的HTTP状态码是否正常方法
ok(){
    const xhr = this.xhr;
    return (xhr.status>=200&&xhr.status<300)||xhr.status===304
}
//在地址上添加数据
addParam(){
   const{params} = this.options;
   if(!params) return '';
   return addURLData(this.url,serialize(params))
}
//设置responseType
setResponseType(){
    this.xhr.responseType = this.options.responseType;
}
//设置跨域是否携带Cookie
setCookie(){
    if(this.xhr.withCredentials){
        this.xhr.withCredentials=true;
    }  
}
//设置超时
setTimeout(){
    const {timeoutTime}=this.options;
    if(timeoutTime > 0){
        this.xhr.timeout = timeoutTime;
    }
}
//发送请求
sendData(){
    const xhr = this.xhr;
    if(!this.isSendData()){
        return xhr.send(null);
    }
    let resultData = null;
    const {data} = this.options;
    //发送FormData格式的数据
    if(this.isFormData()){
        resultData = data;
    }else if(this.isFormURLEncodedData()){
    //发送application/x-www-form-urlencoded格式的数据
    this.setContentType(CONTENT_TYPE_FORM_URLENCODED);
    resultData = serialize(data);
    }else if(this.isJSONData()){
        //发送application/json格式的数据
        this.setContentType(CONTENT_TYPE_JSON);
        resultData = serializeJSON(data)
    }else{
        //发送其他格式数据
        this.setContentType();
        resultData = data;
    }


    xhr.send(resultData)
}
//是否需要send发送数据
isSendData(){
    const {data,method} = this.options;
    if(!data) return false;
    if(method.toLowerCase()===HTTP_GET.toLowerCase()) return false;
    return true;
}
//是否发送FormData格式的数据
isFormData(){
    return this.options.data instanceof FormData;
}
 //是否发送application/x-www-form-urlencoded格式的数据
isFormURLEncodedData(){
 return this.options.contentType.toLowerCase().includes(CONTENT_TYPE_FORM_URLENCODED);
}
//是否发送application/json格式的数据
isJSONData(){
    return this.options.contentType.toLowerCase().includes(CONTENT_JSON);
}
//设置content-type
setContentType(contentType = this.options.contentType){
if(!contentType) return;
this.xhr.setRequestHeader('Content-Type',contentType)
}
//获取XHR对象
getXHR(){
    return this.xhr;
}
}
export default Ajax;

2.封装常量constant.js

//常量
export const HTTT_GET= 'GET';
export const CONTENT_TYPE_FORM_URLENCODED='application/x-www-form-urlencoded';
export const CONTENT_JSON='application/json';

3.默认方法defaults.js

//常量
import { HTTT_GET, CONTENT_TYPE_FORM_URLENCODED} from "./constants";


//默认参数
const DEFAULTS = {
    method:'GET',
    //请求头携带的数据
    params:null,
    // params:{
    //     username:'alex',
    //     age:18
    // }
    data:null,
    // data:{
    //     username:'alex',
    //     age:18
    // }
    //data:FormData数据
    contentType:CONTENT_TYPE_FORM_URLENCODED,
    responseType:'',
    timeoutTime:0,
    withCredentials:false,
    
    
    //方法
    success(){},
    httpCodeError(){},
    error(){},
    abort(){},
    timeout(){}
};
export default DEFAULTS ;

4.定义发送接收等方法index.js

import Ajax from "./ajax";

const ajax=(url,options)=>{
 return  new Ajax(url,options).getXHR();
};
const get=(url,options)=>{
    return  ajax(url,{...options,method:'GET'});
   };
const getJSON=(url,options)=>{
    return  (url,{...options,method:'GET',responseType:'json'});
   };
const post=(url,options)=>{
    return  ajax(url,{...options,method:'POST'});
   };
export {ajax,get,getJSON,post};

5.工具函数units.js

//工具函数
//数据序列化成urlencoded格式的字符串
const serialize=param=>{
    const results = [];
    for(const [key,value] of Object.entries(param)){
        results.push('${encodeURIComponent(key)=${encodeURIComponent(value)}');
        return results.join('&');
    }
};
//数据序列化成JSON格式的字符串
const serializeJSON=param=>{
    return JSON.stringify(param);
}
//给URL添加参数
//www.imooc.com?words=js&
const addURLData = (url,data)=>{
    if(!data) return '';
    const mark = url.includes('?')?'&':'?';
    return '${mark}${data}';
}
export {serialize,addURLData,serializeJSON};

6.index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type='module'>
        // const url = 'https://www.imooc.com/api/http/suggest?words=js'
        // const xhr = new XMLHttpRequest();
        // xhr.addEventListener('load',()=>{
        //     if((xhr.status>=200&&xhr.status<300)||xhr.status===304){
        //         console.log(xhr.responseText);
        //     }
        // },false)
        // xhr.open('GET',url,true);
        // xhr.send(null);
        import {ajax,get,getJSON,post} from './ajax/index.js';
        const url = 'https://www.imooc.com/api/http/suggest?words=js';
        const xhr = ajax(url,{
            method:'POST',
            params:{username:'alex'},
            data:{
                age:18
            },
            responseType:'json',
            success(response){
                console.log(response);
            },
            httpCodeError(err){
                console.log('http code error',err);
            },
            error(xhr){
                console.log('error',xhr);
            },
            abort(xhr){
                console.log('abort',xhr);
            },
            timeout(xhr){
                console.log('timeout',xhr);
            }

        })


    </script>
</html>

4.axios

(1)axios是什么:axios是一个基于Promise的HTTP库,可以用在浏览器和node.js中(本质就是一个第三方Ajax库)。中文官方文档
(2)axios的基本用法:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="https://unpkg.com/axios@0.21.1/dist/axios.min.js"></script>
    <script>
        console.log(axios);
        const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
        axios(url,{
            method:'post',
            //请求时的头信息
            headers:{
                'Content-Type':'application/x-www-form-urlencoded'
            },
            //通过请求头携带的数据
            params:{
                username:'alex'
            },
            //通过请求体携带的数据
            data:'age=18&sex=male',
            withCredientials:true
        }).then(response=>{
            console.log(response);
        }).catch(err=>{
            console.log(err);
        })
    </script>
</body>
</html>

5.Fetch

(1)Fetch是什么:Fetch也是前后端通信的一种方式,是Ajax(XMLHttpRequest)的一种替代方案,是基于Promise的。
注:Ajax的兼容性比Fetch好;没有提供abort、timeout。
(2)Fetch的基本用法:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
//         body: (...)
// bodyUsed: false  body只能读一次,读过之后就不能再读了
// headers: Headers {}
// ok: true   如果ok属性为true,表示可读取数据,不用再判断HTTP状态码
// redirected: false
// status: 200
// statusText: "OK"
// type: "cors"
// url: "https://www.imooc.com/api/http/search/

//第二个参数是对象,用来配置Fetch
        fetch(url,{
            method:'post',
            body:'username=alex&age=18',
            headers:{
                'Content-Type':'application/x-www-form-urlencoded'
            },
            mode:'cors',
            credentials:'include'
        }).then(response=>{
            console.log(response);
            if(response.ok){
               return  response.json()  //返回json格式
            //    return  response.text()    //返回字符格式
            }else{
                throw new Error(`HTTP CODE异常 ${response.status}`);
            }
        }).then(data=>{
            console.log(data);
        }).catch(err=>{
            console.log(err);
        })
    </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值