• 使用 Fetch完成AJAX请求


    使用 Fetch完成AJAX请求

    写在前面

    无论用JavaScript发送或获取信息,我们都会用到Ajax。Ajax不需要刷新页面就能发送和获取信息,能使网页实现异步更新。

    几年前,初始化Ajax一般使用jQuery的ajax方法:

    $.ajax('some-url', {
      success: (data) => { /* do something with the data */ },
      error: (err) => { /* do something when an error happens */}
    });
    

    也可以不用jQuery,但不得不使用XMLHttpRequest,然而这是[相当复杂]

    幸亏,浏览器现在支持Fetch API,可以无须其他库就能实现Ajax

    浏览器支持

    fetch是相对较新的技术,当然就会存在浏览器兼容性的问题,当前各个浏览器低版本的情况下都是不被支持的,因此为了在所有主流浏览器中使用fetch 需要考虑 fetch 的 polyfill 了

    require('es6-promise').polyfill();
    require('isomorphic-fetch');
    

    引入这两个文件,就可以支持主流浏览器了

    Fetch获取数据解读

    使用Fetch获取数据很容易。只需要Fetch你想获取资源。

    假设我们想通过GitHub获取一个仓库,我们可以像下面这样使用:

    fetch('https://api.github.com/users/chriscoyier/repos');
    

    Fetch会返回Promise,所以在获取资源后,可以使用.then方法做你想做的。

    fetch('https://api.github.com/users/chriscoyier/repos')
      .then(response => {/* do something */})
    

    如果这是你第一次遇见Fetch,也许惊讶于Fetch返回的response。如果console.log返回的response,会得到下列信息:

    {
      body: ReadableStream
      bodyUsed: false
      headers: Headers
      ok : true
      redirected : false
      status : 200
      statusText : "OK"
      type : "cors"
      url : "http://some-website.com/some-url"
      __proto__ : Response
    }
    

    可以看出Fetch返回的响应能告知请求的状态。从上面例子看出请求是成功的(oktruestatus是200),但是我们想获取的仓库名却不在这里。

    显然,我们从GitHub请求的资源都存储在body中,作为一种可读的流。所以需要调用一个恰当方法将可读流转换为我们可以使用的数据。

    Github返回的响应是JSON格式的,所以调用response.json方法来转换数据。

    还有其他方法来处理不同类型的响应。如果请求一个XML格式文件,则调用response.text。如果请求图片,使用response.blob方法。

    所有这些方法(response.json等等)返回另一个Promise,所以可以调用.then方法处理我们转换后的数据。

    fetch('https://api.github.com/users/chriscoyier/repos')
      .then(response => response.json())
      .then(data => {
        // data就是我们请求的repos
        console.log(data)
      });
    

    可以看出Fetch获取数据方法简短并且简单。

    接下来,让我们看看如何使用Fetch发送数据。

    Fetch发送数据解读

    使用Fetch发送也很简单,只需要配置三个参数。

    fetch('some-url', options);
    

    第一个参数是设置请求方法(如postputdel),Fetch会自动设置方法为get

    第二个参数是设置头部。因为一般使用JSON数据格式,所以设置ContentTypeapplication/json

    第三个参数是设置包含JSON内容的主体。因为JSON内容是必须的,所以当设置主体时会调用JSON.stringify

    实践中,post请求会像下面这样:

    let content = {some: 'content'};
    
    // The actual fetch request
    fetch('some-url', {
      method: 'post',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(content)
    })
    // .then()...
    

    API

    fetch(url, { // url: 请求地址
        method: "GET", // 请求的方法POST/GET等
        headers: { // 请求头(可以是Headers对象,也可是JSON对象)
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        },
        body: , // 请求发送的数据 blob、BufferSource、FormData、URLSearchParams(get或head方法中不能包含body)
        cache: 'default', // 是否缓存这个请求
        credentials: 'same-origin', //要不要携带 cookie 默认不携带 omit、same-origin 或者 include
        mode: "",
        /*  
            mode,给请求定义一个模式确保请求有效
            same-origin:只在请求同域中资源时成功,其他请求将被拒绝(同源策略)
            cors : 允许请求同域及返回CORS响应头的域中的资源,通常用作跨域请求来从第三方提供的API获取数据
            cors-with-forced-preflight:在发出实际请求前执行preflight检查
            no-cors : 目前不起作用(默认)
    
        */
    }).then(resp => {
        /*
            Response 实现了 Body, 可以使用 Body 的 属性和方法:
    
            resp.type // 包含Response的类型 (例如, basic, cors).
    
            resp.url // 包含Response的URL.
    
            resp.status // 状态码
    
            resp.ok // 表示 Response 的成功还是失败
    
            resp.headers // 包含此Response所关联的 Headers 对象 可以使用
    
            resp.clone() // 创建一个Response对象的克隆
    
            resp.arrayBuffer() // 返回一个被解析为 ArrayBuffer 格式的promise对象
    
            resp.blob() // 返回一个被解析为 Blob 格式的promise对象
    
            resp.formData() // 返回一个被解析为 FormData 格式的promise对象
    
            resp.json() // 返回一个被解析为 Json 格式的promise对象
    
            resp.text() // 返回一个被解析为 Text 格式的promise对象
        */
        if (resp.status === 200) return resp.json();
        // 注: 这里的 resp.json() 返回值不是 js对象,通过 then 后才会得到 js 对象
        throw New Error('false of json');
    }).then(json => {
        console.log(json);
    }).catch(error => {
        consolr.log(error);
    })
    

    常用情况

    1.请求 json

    fetch('http://xxx/xxx.json').then(res => {
            return res.json();
        }).then(res => {
            console.log(res);
        })
    

    2. 请求文本

    fetch('/xxx/page').then(res => {
            return res.text();
        }).then(res => {
            console.log(res);
        })
    

    3. 发送普通json数据

     fetch('/xxx', {
            method: 'post',
            body: JSON.stringify({
                username: '',
                password: ''
            })
        });
    

    4. 发送Form表单数据

    var form = document.querySelector('form');
        fetch('/xxx', {
            method: 'post',
            body: new FormData(form)
        });
    

    5. 获取图片

     fetch('/xxx').then(res => {
            return res.blob();
        }).then(res => {
            document.querySelector('img').src = URL.createObjectURL(imageBlob);
        })
    
    

    6. 上传文件

        var file = document.querySelector('.file')
        var data = new FormData()
        data.append('file', file.files[0])
        fetch('/xxx', {
          method: 'POST',
          body: data
        })
    
    

    7. 封装

        require('es6-promise').polyfill();
        require('isomorphic-fetch');
    
        export default function request(method, url, body) {
            method = method.toUpperCase();
            if (method === 'GET') {
                body = undefined;
            } else {
                body = body && JSON.stringify(body);
            }
    
            return fetch(url, {
                method,
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                body
            }).then((res) => {
                if (res.status >= 200 && res.status < 300) {
                    return res;
                } else {
                    return Promise.reject('请求失败!');
                }
            })
        }
    
        export const get = path => request('GET', path);
        export const post = (path, body) => request('POST', path, body);
        export const put = (path, body) => request('PUT', path, body);
        export const del = (path, body) => request('DELETE', path, body);
    

    参考

    总结

    Fetch是很好的方法,能发送和接收数据。不需要在编写XHR请求或依赖于jQuery。

    尽管Fetch很好,但是其错误处理不是很直接。在处理之前,需要让错误信息进入到catch方法中。

    听说有个zlFetch库,改善了Fetch错误处理de问题。

    But ! 现在有了Axios了,还跟我扯啥犊子呢!直接一步到位用Axios吧小盆友~

  • 相关阅读:
    oracle权限配置
    oracle锁表处理
    小组成员
    个人项目 Individual Project
    Java单元测试框架 JUnit
    MyEclipse的快捷键大全(超级实用,方便)
    vs2008 连接 vss2005 出现 analyze utility 错误的解决方法
    EXTJS gridpanel 动态设置表头
    IE8不能上网的问题
    一些事件的评论
  • 原文地址:https://www.cnblogs.com/wenqiangit/p/9918042.html
Copyright © 2020-2023  润新知