Fetch——HTTP请求之一

235 阅读3分钟

一般使用XHR进行异步访问、获取资源会有以下几个步骤:

创建对象、设置请求函数和回调函数、获取异步对象的readyState属性、判断响应报文的状态、读取响应数据。

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "/try/ajax/demo_get.php", true);
/*xmlhttp.onload = () => {   // 响应的状态码为4
    var data = JSON.parse(this.responseText);
    console.log(data);
}*/
xmlhttp.onerror = () => {
    console.log(err);
}
xmlhttp.send();
xmlhttp.onreadystatechange = function () {
	if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
		document.getElementById("mydiv").innerHTML = xmlhttp.responseText;
	}
}
  • 状态码

    0:请求未初始化

    1:服务器连接已建立

    2:请求已接受

    3:请求已处理

    4:请求已完成,且响应已就绪

状态码为2、3和4时进入onreadystatechange,而对于onload,只有状态码为4才能进入。

  • 实现加载请求中相关——onprogress

    function loadText(){
    	let xhr = new XMLHttpRequest();
        xhr.open('GET','sample.txt',true);
        console.log("READYSTATE"+ xhr.readyState); // 1
        //两种请求方式onload和onreadystatechange
        xhr.onprogress = function(){
        	console.log("测试加载状态READYSTATE"+ xhr.readyState); // 3
        }
        xhr.onload = function(){
            console.log("READYSTATE"+ xhr.readyState); //4
            console.log(this.responseText);
        }
        xhr.send();
    }
    

Fetch

使用语法

fetch是基于promise的,fetch方法必须接受一个参数——资源的路径URL,返回一个promise对象,resolve对应请求的response

fetch(url,options).then((response)=>{
//处理http响应
},(error)=>{
//处理错误
})

options:发送请求参数,

  • body - http请求参数
  • mode - 指定请求模式。默认值为cros:允许跨域;same-origin:只允许同源请求;no-cros:只限于getposthead,并且只能使用有限的几个简单标头。
  • cache - 用户指定缓存。
  • method - 请求方法,默认GET
  • signal - 用于取消 fetch
  • headers - http请求头设置
  • keepalive - 用于页面卸载时,告诉浏览器在后台保持连接,继续发送数据。
  • credentials - cookie设置,默认omit,忽略不带cookiesame-origin同源请求带cookieinclue无论跨域还是同源都会带cookie

读取内容方法

fetch请求成功后会获取到response响应对象:

img

  • status - http状态码,范围在100-599之间
  • statusText - 服务器返回状态文字描述
  • ok - 返回布尔值,如果状态码2开头的,则true,反之false
  • headers - 响应头
  • body - 响应体。响应体内的数据,根据类型各自处理。
  • type - 返回请求类型。
  • redirected - 返回布尔值,表示是否发生过跳转。

response对象对于服务器返回的不同类型的数据有着不同的读取方法,并且这些方法都返回一个promise对象:

  • response.text() -- 得到文本字符串
  • response.json() - 得到 json 对象
  • response.blob() - 得到二进制 blob 对象
  • response.formData() - 得到 formData 表单对象
  • response.arrayBuffer() - 得到二进制 arrayBuffer 对象

get请求和post请求

  • get请求

    // 通过fetch获取百度的错误提示页面
    fetch('https://www.baidu.com/search/error.html?a=1&b=2', { // 在URL中写上传递的参数
        method: 'GET' // 默认为get
      })
      .then((res)=>{
        return res.text()
      })
      .then((res)=>{
        console.log(res)
      })
    
  • post请求

    // 通过fetch获取百度的错误提示页面
    fetch('https://www.baidu.com/search/error.html', {
        method: 'POST',
        headers: new Headers({
          'Content-Type': 'application/x-www-form-urlencoded' // 指定提交方式为表单提交
        }),
        body: new URLSearchParams([["foo", 1],["bar", 2]]).toString()
      })
      .then((res)=>{
        return res.text()
      })
      .then((res)=>{
        console.log(res)
      })
    

    post请求的参数为了防止信息泄露时不能放在URL中的。post请求默认的提交方式是Content-Type:text/plain;charset=UTF-8,但我们一般使用表单提交,所以我们可以指定头信息为application/x-www-form-urlencoded

cookie相关

fetch在默认情况下是不会从服务端接收任何cookies的,要发送cookies的话就必须发送凭据头。

// 通过fetch获取百度的错误提示页面
fetch('https://www.baidu.com/search/error.html', {
    method: 'GET',
    credentials: 'include' // 强制加入凭据头
  })
  .then((res)=>{
    return res.text()
  })
  .then((res)=>{
    console.log(res)
  })

封装fetch

/**
 * 将对象转成 a=1&b=2的形式
 * @param obj 对象
 */
function obj2String(obj, arr = [], idx = 0) {
  for (let item in obj) {
    arr[idx++] = [item, obj[item]]
  }
  return new URLSearchParams(arr).toString()
}

/**
 * 真正的请求
 * @param url 请求地址
 * @param options 请求参数
 * @param method 请求方式
 */
function commonFetcdh(url, options, method = 'GET') {
  const searchStr = obj2String(options)
  let initObj = {}
  if (method === 'GET') { // 如果是GET请求,拼接url
    url += '?' + searchStr
    initObj = {
      method: method,
      credentials: 'include'
    }
  } else {
    initObj = {
      method: method,
      credentials: 'include',
      headers: new Headers({
        'Accept': 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded'
      }),
      body: searchStr
    }
  }
  fetch(url, initObj).then((res) => {
    return res.json()
  }).then((res) => {
    return res
  })
}

/**
 * GET请求
 * @param url 请求地址
 * @param options 请求参数
 */
function GET(url, options) {
  return commonFetcdh(url, options, 'GET')
}

/**
 * POST请求
 * @param url 请求地址
 * @param options 请求参数
 */
function POST(url, options) {
  return commonFetcdh(url, options, 'POST')
}


// 例子
GET('https://www.baidu.com/search/error.html', {a:1,b:2})
POST('https://www.baidu.com/search/error.html', {a:1,b:2})