无论用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 浏览器支持 桌面浏览器 [图片上传失败...(image-876b64-1534213182911)] 手机/平板电脑 [图片上传失败...(image-5c90b9-1534213182911)] 所有主要的浏览器(除了Opera Mini和老的IE)都支持Fetch。针对不支持的,可以使用Fetch polyfill 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返回的响应能告知请求的状态。从上面例子看出请求是成功的(ok是true,status是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);

第一个参数是设置请求方法(如post、put或del),Fetch会自动设置方法为get。 第二个参数是设置头部。因为一般使用JSON数据格式,所以设置ContentType为application/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()...

Fetch处理异常 虽然希望Ajax响应成功,但是仍会有问题出现:

可能尝试获取不存在的资源 没有权限获取资源 输入参数有误 服务器抛出异常 服务器超时 服务器崩溃 API更改 ...

假设我们试图获取不存在错误,并了解如何处理错误。下面的例子我将chriscoyier拼错为chrissycoyier // 获取chrissycoyier's repos 而不是 chriscoyier's repos fetch('https://api.github.com/users/chrissycoyier/repos')

为了处理此错误,我们需要使用catch方法。 也许我们会用下面这种方法: fetch('https://api.github.com/users/chrissycoyier/repos') .then(response => response.json()) .then(data => console.log('data is', data)) .catch(error => console.log('error is', error));

然而却得到下面这样结果:

image

获取失败,但是第二个.then方法会执行。 如果console.log此次响应,会看出不同: { body: ReadableStream bodyUsed: true headers: Headers ok: false // Response is not ok redirected: false status: 404 // HTTP status is 404. statusText: "Not Found" // Request not found type: "cors" url: "https://api.github.com/users/chrissycoyier/repos" }

大部分是一样的,只有ok、status和statusText是不同的,正如所料,GitHub上没有发现chrissycoyier。 上面响应告诉我们Fetch不会关心AJAX是否成功,他只关心从服务器发送请求和接收响应,如果响应失败我们需要抛出异常。 因此,初始的then方法需要被重写,以至于如果响应成功会调用response.json。最简单方法是检查response是否为ok。 fetch('some-url') .then(response => { if (response.ok) { return response.json() } else { // Find some way to get to execute .catch() } });

一旦我们知道请求是不成功的,我可以throw异常或rejectPromise来调用catch。 // throwing an Error else { throw new Error('something went wrong!') }

// rejecting a Promise else { return Promise.reject('something went wrong!') }

这里选择Promise.reject,是因为容易扩展。抛出异常方法也不错,但是无法扩展,唯一益处在于便于栈跟踪。 所以,到现在代码应该是这样的: fetch('https://api.github.com/users/chrissycoyier/repos') .then(response => { if (response.ok) { return response.json() } else { return Promise.reject('something went wrong!') } }) .then(data => console.log('data is', data)) .catch(error => console.log('error is', error));

image

这样错误就会进入catch语句中。 但是rejectPromise时,只输出字符串不太好。这样不清楚哪里出错了,你肯定也不会想在异常时,输出下面这样:

image

让我们在看看响应: { body: ReadableStream bodyUsed: true headers: Headers ok: false // Response is not ok redirected: false status: 404 // HTTP status is 404. statusText: "Not Found" // Request not found type: "cors" url: "https://api.github.com/users/chrissycoyier/repos" }

在这个例子中,我们知道资源是不存在。所以我们可以返回404状态或Not Found原因短语,然而我们就知道如何处理。 为了在.catch中获取status或statusText,我们可以reject一个JavaScript对象: fetch('some-url') .then(response => { if (response.ok) { return response.json() } else { return Promise.reject({ status: response.status, statusText: response.statusText }) } }) .catch(error => { if (error.status === 404) { // do something about 404 } })

上面的错误处理方法对于下面这些不需要解释的HTTP状态很适用。

401: Unauthorized 404: Not found 408: Connection timeout ...

但对于下面这些特定的错误不适用:

400:Bad request 例如,如果请求错误缺少必要的参数,就会返回400.

image

光在catch中告诉状态及原因短语并不足够。我们需要知道缺少什么参数。 所以服务器需要返回一个对象,告诉造成错误请求原因。如果使用Node和Express,会返回像下面这样的响应:

res.status(400).send({ err: 'no first name' })

无法在最初的.then方法中reject,因为错误对象需要response.json来解析。 解决的方法是需要两个then方法。这样可以首先通过response.json读取,然后决定怎么处理。 fetch('some-error') .then(handleResponse)

function handleResponse(response) { return response.json() .then(json => { if (response.ok) { return json } else { return Promise.reject(json) } }) }

首先我们调用response.json读取服务器发来的JSON数据,response.json返回Promise,所以可以链式调用.then方法。 在第一个.then中调用第二个.then,因为我们仍希望通过repsonse.ok判断响应是否成功。 如果想发送状态和原因短语,可以使用Object.assign()将二者结合为一个对象。 let error = Object.assign({}, json, { status: response.status, statusText: response.statusText }) return Promise.reject(error)

可以使用这样新的handleResponse函数,让数据能自动的进入.then和.catch中。 fetch('some-url') .then(handleResponse) .then(data => console.log(data)) .catch(error => console.log(error))

处理其他响应类型 到现在,我们只处理JSON格式的响应,而返回JSON格式数据大约占90%。 至于其他的10%呢? 假设上面的例子返回的是XML格式的响应,也许会收到下面异常:

image

这是因为XML格式不是JSON格式,我们无法使用response.json,事实上,我们需要response.text,所以我们需要通过判断响应的头部来决定内容格式: .then(response => { let contentType = response.headers.get('content-type')

if (contentType.includes('application/json')) { return response.json() // ... }

else if (contentType.includes('text/html')) { return response.text() // ... }

else { // Handle other responses accordingly... } });

当我遇见这种问题时,我尝试使用ExpressJWT处理身份验证,我不知道可以发生JSON响应数据,所以我将XML格式设为默认。 这是我们到现在完整代码: fetch('some-url') .then(handleResponse) .then(data => console.log(data)) .then(error => console.log(error))

function handleResponse (response) { let contentType = response.headers.get('content-type') if (contentType.includes('application/json')) { return handleJSONResponse(response) } else if (contentType.includes('text/html')) { return handleTextResponse(response) } else { // Other response types as necessary. I haven't found a need for them yet though. throw new Error(Sorry, content-type ${contentType} not supported) } }

function handleJSONResponse (response) { return response.json() .then(json => { if (response.ok) { return json } else { return Promise.reject(Object.assign({}, json, { status: response.status, statusText: response.statusText })) } }) } function handleTextResponse (response) { return response.text() .then(text => { if (response.ok) { return json } else { return Promise.reject({ status: response.status, statusText: response.statusText, err: text }) } }) }

介绍zlFetch zlFetch库就是上例中handleResponse函数,所以可以不用生成此函数,不需要担心响应来处理数据和错误。 典型的zlfetch像下面这样: zlFetch('some-url', options) .then(data => console.log(data)) .catch(error => console.log(error));

使用之前,需要安装zlFetch npm install zl-fetch --save

接着,需要引入到你的代码中,如果你需要polyfill,确保加入zlFetch之前引入它。 // Polyfills (if needed) require('isomorphic-fetch') // or whatwg-fetch or node-fetch if you prefer

// ES6 Imports import zlFetch from 'zl-fetch';

// CommonJS Imports const zlFetch = require('zl-fetch');

zlFetch还能无须转换成JSON格式就能发送JSON数据。 下面两个函数做了同样事情,zlFetch加入Content-type然后将内容转换为JSON格式。 let content = {some: 'content'}

// Post request with fetch fetch('some-url', { method: 'post', headers: {'Content-Type': 'application/json'} body: JSON.stringify(content) });

// Post request with zlFetch zlFetch('some-url', { method: 'post', body: content });

zlFetch处理身份认证也很容易。 常用方法是在头部加入Authorization,其值设为Bearer your-token-here。如果你需要增加token选项,zlFetch会帮你创建此域。 所以,下面两种代码是一样的: let token = 'someToken' zlFetch('some-url', { headers: { Authorization: Bearer ${token} } });

// Authentication with JSON Web Tokens with zlFetch zlFetch('some-url', {token});

下面就是使用zlFetch来从GitHub上获取repos:

作者:小豆soybean 链接:https://www.jianshu.com/p/4339f724de65 来源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://my.oschina.net/jsycwangwei/blog/3090059

浏览器模拟请求指令fetch相关推荐

  1. 简单实用的Chrom浏览器模拟POST请求方式

    实现post请求方式有很多种,比如postman等. 但有时候接口做了登录拦截,这个时候使用postman等工具要配置相关的cookie信息. 这个过程是很繁琐,最后也不一定能达到预期效果. 本篇使用 ...

  2. pythonrequests发送数据_在python中使用requests 模拟浏览器发送请求数据的方法

    在python中使用requests 模拟浏览器发送请求数据的方法 如下所示: import requests url='http://####' proxy={'http':'http://#### ...

  3. PHP curl模拟ip与模拟浏览器header请求方法

    一.准备一个接收文件ipb.php 1.代码: <?php /*** 接收请求信息写入日志* Date: 2018/12/25*/ ini_set('date.timezone', 'Asia/ ...

  4. Python 模拟浏览器 POST请求思路

    Python 模拟浏览器发送POST请求思路 昨天朋友找我说想对一个tp网站的视频刷播放量,说可以一个IP地址无限刷. 登陆到网站后对所需的视频进行点击播放,发现没有任何跳转,而是发送了个POST请求 ...

  5. java模拟浏览器http请求_java使用HttpClient模拟浏览器请求

    代码如下,模仿10000次请求,为什么只成功了3次,求指教 按题主的代码,在第三次请求中,创建 HttpClientConnection 对象时就已经阻塞了,只成功3次实属正常(第三次是浏览器的请求) ...

  6. XHR请求与fetch请求

    文章目录 一.XMLHttpRequest对象 1.使用XHR (1).代码示例 (2).GET请求 (3).POST请求 (4).注意事项 2.XMLHttpRequest Level 2 (1). ...

  7. CURL模拟请求(get/post)

    [先知] http协议是客户端和服务端数据交互而定的规范. 具有如下特点:1.一般是基于B/S结构访问.2.无状态服务端没有记忆功能,不能识别客户端.3.无连接主要是在说http 1.0,它是短连接, ...

  8. fiddler抓取谷歌浏览器的包_fiddler抓不到chrome浏览器的请求

    今天遇到一个非常尴尬的问题,接口在某种情况下会报错,此时前端会展示NAN之类的东西,由于复现不了,接口现在一直不报 错了,所以就让前端做了个友好提示, 当接口报错时,给个提示"请稍后重试&q ...

  9. Ajax请求,JQuery发送请求,Axios请求,Fetch请求总结

    常见的请求方式 1.Ajax请求 定义: 同步与异步的区别: Ajax的工作原理: 实现AJAX的基本步骤: Get请求: Post请求: 2.JQuery发送请求 Get请求: Post请求: 3. ...

最新文章

  1. 关于Socket通信客户端是否需要绑定端口号
  2. 如何在同一台电脑上多个账户同时登陆MSN
  3. Zencart修改前台页面的字体颜色
  4. Python 3.9,来了!
  5. 把canvas标签里的图像下载成本地图片文件
  6. matlab 最小二乘法拟合_计量与论文串讲:最小二乘法
  7. 【Clickhouse】Clickhouse 数据字典
  8. 模拟器显示空白图片_网吧模拟器下载:小游戏礼包
  9. ajax请求怎么判断没有更多内容,怎么知道ajax 请求完了,想在数据没请求完时,页面有一个loading效果...
  10. python 排队论_建模算法(七)——排队论模型
  11. 基于matlab实现人脸识别解析
  12. 《塞尔达传说》系列游戏评测
  13. vue中如何引入公共样式的的styl文件
  14. 制动计算机,一种基于摩擦制动的计算机主机底座
  15. UC手机浏览器(U3内核)相关文档整理
  16. 下载谷歌浏览器以及谷歌浏览器不能加载网页问题的解决
  17. 数据中台建设(规划篇)
  18. Linux时间编程三大步骤
  19. 夏天甲醛超标已入住怎么办呀 ?专业清除甲醛方法和技巧!
  20. mysql数据库画拓扑图_echartsjs制作的mysql应用架构拓扑图,数据库架构图

热门文章

  1. 用友t6服务器设置映射,能否自定义用友T6 ERP-接口字段映射设置?
  2. Linux入门级别知识详解(二)
  3. javaweb基于SSH开发库尔勒市经济技术开发区电子政务网站+论文 毕业设计
  4. 一个前端失败者的自我剖析与反思
  5. chatGPT是什么?chatGPT有哪些应用场景
  6. 音乐播放上一首,下一首
  7. mindjet使用技巧
  8. 希尔伯特曲线 java_《算法心得:高效算法的奥秘》PDF 下载
  9. JDK官网下载又慢又繁琐?试试华为云上下载各个版本的JDK吧
  10. win10任务栏点击没反应