【Ajax异步交互与跨域访问】实现跨域访问和axios库

实现跨域访问

一. 跨域访问

  • URL地址:

    URL地址:网络协议 + 域名(IP地址) + 端口号 + 资源路径

    • 同源:网络协议相同、域名相同以及端口相同
    • 不同源:
    • 域名不相同:完全跨域
    • 域名相同,端口号不一样:跨子域
    • 互联网默认原则(同源策略)不允许跨域访问
  • 通源策略

    1995年,同源政策由Netscape公司引入游览器。现在所有游览器都实行这个政策。

    同源指“三个相同”:协议相同、域名相同和接口相同

    • 同源策略的作用:
    • 保证用户信息安全
    • 防止恶意的网站窃取数据
    • 如果不是同源的话,会有三种行为受限:
    1. Cookie、LocalStorage和IndexDB无法读取
    2. DOM无法获得
    3. Ajax请求不能发送
  • 跨域

    一个资源从资源本身所在服务器不同的域或端口请求一个资源时,资源会发起一个跨域HTTP请求。

    游览器限制从脚本发起的跨域HTTP请求,所以有些API的Web应用程序只能从加载应用程序的一个域请求HTTP资源

    • 常见跨域类型:
    • 完全跨域:一个顶级域名方向另一个停机域名
    • 跨子域:相同顶级域名下的两个子级域名互相通信
    • 跨域元素
    • HTML页面中一些允许指定路径的元素具有跨域特性
      • link
      • script
      • img
      • iframe

二. JSONP解决跨域

  • JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决游览器的跨域问题

    JSONP的使用模式就是利用<script>元素的开放策略,使游览器可以获得其他来源动态产生的JSON资料

    • 数据必须是JSON格式
  • 过程

    游览器:

    1. 创建一个函数,定义形参,用于接收服务器返回的数据
    <script>
      // 定义发送服务器端
      function fn(data){
          console.log(data)
      }
    </script>
    
    1. 利用script元素的开放策略,向指定服务器地址发送跨域访问请求,并携带回调函数的名称
    <script src="http://127.0.0.1:8088?callback=fn"></script>
    

    服务器:

    1. 接收游览器页面发送的跨域访问请求
    2. 将响应数据构建成JSON格式,并将数据放置在回调函数中进行传递
    res.end('fn({"msg":"HELLO WORLD"})');
    

    先编写回调函数的调用语法,然后将数据作为回调函数的实参

    1. 完整代码
    const http = require('http'); // 引入HTTP模块
    
    // 创建一个服务
    const server = http.createServer((req,res)=>{  
      res.statusCode = 200;
      res.setHeader('Content-Type','text/plain');
      
      // 响应页面请求
      res.end('fn({"msg":"HELLO WORLD"})');
    })
    
    // 开启服务器
    server.listen(8088,()=>{
      console.log('>>>服务器已开启,端口号8088')
    })
    

三. jQuery实现跨域访问

  • jQuery中$.getJSON()方法可以通过使用JSON形式的回调函数来加载其他网域的JSON数据

    • $.getJSON()第一个参数为URL,要在后面添加’callback=?’, jQuery会自动把?改为正确的函数名
  • 客户端

     $.getJSON('http://127.0.0.1:8088?callback=?',function(data){
         console.log(data)
     });
    
  • 服务器

    const http = require('http'); // 引入HTTP模块
    
    // 创建一个服务
    /*
        req---表示请求
        res---表示响应
    */ 
    const server = http.createServer((req,res)=>{
        var url = req.url; 
        var urlObj = require('url').parse(url); 
        var functionName = urlObj.query.split('&')[0].split('=')[1]; 
        
        res.statusCode = 200;
        res.setHeader('Content-Type','text/plain');
        /**
         * 响应页面请求
         * - 响应的数据必须是JSON格式
         * - 将响应数据放在回调函数中
         */
        // res.end('fn({"msg":"HELLO WORLD"})');
        res.end(functionName + '({"msg":"HELLO WORLD"})');
    
    })
    
    // 开启服务器
    server.listen(8088,()=>{
        console.log('>>>服务器已开启,端口号8088')
    })
    

Axios库

一. axios是继承语法

Axios是一个类库,基于PROMISE管理的AJAX库

提供了对应的请求方法如: GET\POST\HEAD\PUT\DELETE…

axios.get() 向服务器发送一个请求,基于GET方法

axios.post() 向服务器发送一个请求,基于POST方法

  • 基于GET或者POST方法请求,返回的结果都是PROMISE实例

安装Axios:

  • 直接npm install axios --save安装
  • 或者先安装yarn npm i -g yarn 然后 yarn add axios

例子:

  • get方法
axios.get('http://127.0.0.1:8088/',{
    params:{
        name:'admin',
        age:26
    }
});
  • post方法
axios.post('http://127.0.0.1:8088/add', {
    params: {
        name: 'admin',
        age: 26
    }
});
  • 解决回调地狱
axios.get('http://127.0.0.1:8088/',{
    params:{
        name:26
    }
}).then(result =>{
    let {data} = result;

    return axios.post('http://127.0.0.1:8088/')
}).then(result => {
    let {data} = result;
    console.log(data);
})

二. axios请求合并

  • 两个请求都执行成功后才执行
  • 普通写法
let result = null;
axios.get("A").then(resultA =>{
 result = resultA; // 把A的结果给全局的result
 return axios.get('B');
}).then(resultB => {
 // A和B都执行完毕后才执行
})
  • axios的all方法
// 保存了Ajax请求实例的数组
let sendAry=[ 
 axios.get('http://127.0.0.1:8088/'),
 axios.post('http://127.0.0.1:8088/add')
]

axios的all()方法
axios.all(sendAry).then(result =>{
  console.log(result); // 分别存了两个请求的结果
})

三. axios常用配置项

  • 初始化路径

    axios.defaults.baseURL = 'http://127.0.0.1:8088';
    
  • 设置响应拦截器:分别在响应成功和失败的时候做一些拦截处理

       //axios.interceptors.response.use(function success(result){
           //return result.data
       //}
    
       // 箭头函数写法
       axios.interceptors.response.use(result => result.data)                   
    
  • 自定义请求成功失败规则

    // axios.defaults.validateStatus = function validateStatus(status){
    //     return /^(2|3)\d{2}$/.test(status);
    // }
    
    // 箭头函数写法
    axios.defaults.validateStatus = status => /^(2|3)\d{2}$/.test(status);
    
  • 设置在post请中向服务器发送内容的格式,默认RAW,常用为URL-ENCODEED格式

    axios.defaults.headers['Content-Type'] = 'appliction/x-www-form-urlencoded';
    axios.defaults.transformRequest = data =>{
        let str = '';
        for (let attr in data){
            if(data.hasOwnProperty(attr)){
                str += '${attr}=${data[attr]}&';
            }
        }
        return str.substring(0, str.length - 1);
    }
    
  • 不适合设置成全局的配置项

    // 设置时间
    axios.defaults.timeout = 3000;
    // 自定义请求头
    axios.defaults.headers ={
    	name:'admin'
    }
    // get传参
    axios.defaults.params = {};
    // post传参
    axios.defaults.data= {};
    

四.Fetch

Fetch不是Ajax,是为了代替Ajax而存在的,是JS里内置的API。可以通过Fetch实现客户端和服务端的信息通信。

  • ES2018规范中新增的Fetch,游览器支持度可能不好,可以基于BABEL的最新语法解析包进行解析
  • 例子
// get方法
fetch('http://127.0.0.1:8088/').then(result=>{
    let {status} = result;
    if(/^(4|5)\d{2}$/.test(status)){
        throw new Error('query data is error')
        return;
    }
    return result.json();
}).then(result =>{
    console.log(result);
}).catch(msg =>{
    console.log(msg);
})

五. 基于promise创建ajax库

  • 首先设置好默认配置项

        let _default = {
            method: 'GET',
            url: '',
            baseURL: '',
            headers: {},
            dataType: 'JSON',
            data: null, // POST系列请求基于请求主体传递给服务器的内容
            params: null, // GET系列请求基于问号传参传递给服务器的内容
            cache: true
        };
    
    // 把默认配置暴露出去,使用户可以自己修改值
        ajaxPromise.defaults = _default;
    
  • 要用到的方法

    // 把对象变为URLENCODE格式的字符串
        ajaxPromise.formatData = function formatData(obj){
            let str = "";
            for(let attr in obj){
                if(obj.hasOwnProperty(attr)){
                    str += `${attr}=${obj[attr]}&`
                }
            }
            return str.substring(0,str.length - 1);
        };
    
        ajaxPromise.check = function check(url){
            return url.indexOf('?') > -1 ? '&' : '?';
        };
    
  • ajax请求相关

    let ajaxPromise = function ajaxPromise(options) {
            // options中融合了默认配置信息、用户基于DEFAULTS修改的信息、用户执行GET\POST方法时传递的配置信息
    
            let {
                url,
                baseURL,
                method,
                data,
                dataType,
                headers,
                cache,
                params
            } = options;
    
            // 把参数进一步处理
            if(/^(GET|DELETE|HEAD|OPTIONS)$/i.test(method)){
                // get系列
                if(params){
                    url += `${ajaxPromise.check(url)}${ajaxPromise.formatData(params)}`;
                }
                if(cache === false){
                    url += `${ajaxPromise.check(url)}_=${+(new Date())}`;
                }
                data = null; // get请求主体里没内容
            }else{
                // post
                if(data){
                    data = ajaxPromise.formatData(data);
    
                };
            };
    
            // 基于promise发送AJAX
            return new Promise((resolve, reject) => {
                let xhr = new XMLHttpRequest;
                xhr.open(method, '${baseURL}${url}');
                // 如果HEADERS存在,设置请求头
                if (headers !== null && typeof headers === 'object') {
                    for (let attr in headers) {
                        if (headers.hasOwnProperty(attr)) {
                            let val = headers[attr];
                            if (/[\u4e00-\u9fa5]/.test(val)) {
                                // val中有中文,用encodeURIComponent进行编码
                                val = encodeURIComponent(val);
                            };
                            xhr.setRequestHeader(attr, headers[attr]);
                        };
                    };
                };
                // 设置请求成功条件
                xhr.onreadystatechange = () => {
                    if (xhr.readyState === 4) {
                        if (/^(2|3)\d{2}&/.test(xhr.status)) {
                            let result = xhr.responseText;
                            dataType = dataType.toUpperCase();
                            dataType === 'JSON' ? result = JSON.parse(result) : (dataType === 'XML' ? result = xhr.responseXML : null);
                            resolve(result,xhr);
                            return;
                        };
                        reject(xhr.statusText, xhr);
                    };
                };
                xhr.send(data);
            });
        };
    
  • 请求方法

    // get请求
    ['get', 'delete', 'head', 'options'].forEach(item =>{
        ajaxPromise[item] = function anonymous(url, options = {}){
            options={
                ..._default, // 默认值或default修改的值
                ...options, // 用户调取方法传递的配置项
                url:url, // 请求的url地址
                method: item.toUpperCase() // 以ajaxPromise.method执行
            };
            return ajaxPromise(options);
        };
    });
    
    // post请求 3个参数
    ['post', 'put', 'patch'].forEach(item => {
        ajaxPromise[item] = function anonymous(url,data = {},options = {}) {
            options = {
                ..._default, // 默认值或default修改的值
                ...options, // 用户调取方法传递的配置项
                url: url, // 请求的url地址
                method: item.toUpperCase(), // 以AjaxPromise.method执行
                data:data
            };
            return ajaxPromise(options);
        };
    });
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值