Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >二十分钟封装,一个App前后台Http交互的实现

二十分钟封装,一个App前后台Http交互的实现

原创
作者头像
rufeng008
修改于 2020-05-12 07:14:26
修改于 2020-05-12 07:14:26
1.5K00
代码可运行
举报
文章被收录于专栏:RN 技术RN 技术
运行总次数:0
代码可运行

React Native开发过程中,几乎所有的app都需要使用到Http请求,所以fetch的封装必不可少,由于不同app的请求参数,解析规则,token机制等完全不一样,所以在大多数App开发中,前后台Http请求的实现都是开发者自己封装的。

封装一个前后台Http请求实现需要多久?

可能有人回答是1小时,也有3、5小时甚至更长时间的,或者也有说先这样封装个大概,等到需求不满足的时候再改。

花费1小时的时间不一定短,花费3、5的时间也不一定算长,具体要看前后台交互的复杂程度与开发者对交互实现的封装程度。

那这里我们就引出了一个问题了,我们通常说的app的Http请求【封装】,到底封装的是什么,我们需要做哪些工作,能使用得app的接口请求更简单,易用且有较高的灵活性?在我看来这个“封装”主要分两个部分:

1. 数据交换 层面的封装,即:

  • 实现前后台的互通,支持服务器要求的数据交换类型、格式等
  • 调用者可以自由设置请求的header、params等参数,程序根据不同的设置也能保证请求能正确的发送给服务端并返回相应的结果
  • 支持超时、日志打印等一些基本功能

2. 业务逻辑 层面的封装,即:

  • 入参:公共部分header、params的参数处理,避免在具体接口请求是传入不必要与接口无关的参数
  • 出参:对后台返回的数据按约定好的规则做一层基础解析处理,避免在具体接口数据解析的时候做一些无意义的操作

从投入的时间上来看: 第一部分基本上要花掉开发者80%以上的时间来封装 第二部分需要消耗的时间可能不足20% 【以此推算,按上面1个小时的封装时间,用在逻辑封装部分的时间也就12分钟左右?】

我们再回头看一下,第一部分的【数据交换】封装是否涉及到具体业务逻辑呢?答案是:没有。

既然没有我们为什么不把第一部分的封装交给第三方框架呢,我们只需要做第二部分的封装多省事,有这样第三方框架么?

答案是:有的,react-native-easy-app 就可以实现【前后台数据交换】层面的封装,通过这个开源库,我们就只需要实现涉及【App业务逻辑】层面的封装即可。


为验证 react-native-easy-app 的实用性,在这里我们先来构想一个业务逻辑层面封装的需求:

1. 请求接口的公共headers参数有:

  • version、channelCode、model、platform (所有接口)
  • accessToken、refreshToken、customerId (登录后额外增加)

2. 请求接口的公共params参数有:

  • customerId (登录后额外增加)

3. 后台返回的数据结构示例如下: { data: {}, successful:1, msg: 'request msg', code: 'xxx'}

4. 请求状态码为503的时候表示accessToken过期,accessToken过期的情况下,需要重新获取新的accessToken并刷新因accessToken过期导致请求失败的接口

5. accessToken、refreshToken在登录成功后的response的headers中返回。

对于以上业务逻辑层面的需求,看看通过 react-native-easy-app 我们可以怎么做。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
RFHttpConfig().initHttpLogOn(true)
    .initHeaderSetFunc((headers) => {
        headers['model'] = 'xiao mi';
        headers['version'] = '1.0.0';
        headers['platform'] = Platform.OS;
        headers['channelCode'] = 'channelOfficial';
        if (isLogin()) {
            headers['customerId'] = RNStorage.customerId;
            headers['accessToken'] = RNStorage.accessToken;
            headers['refreshToken'] = RNStorage.refreshToken;
        }
    })
    .initParamSetFunc(params => {
        if (isLogin()) {
            params['customerId'] = RNStorage.customerId;
        }
    })
    .initParseDataFunc((result, request, callback) => {
        let {success, json, message, status, response} = result;
        if (status === 503) {// accessToken过期标记
            this.refreshToken(request, callback);
        } else {
            let {data, successful, msg, code} = json;
            callback(success && successful === 1, data || {}, msg || message, code, response);
        }
    });

accessToken重新请求的实现及对失败接口的刷新:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
refreshToken = (request, callback) => {
    if (global.hasQueryToken) {
        global.tokenExpiredList.push({request, callback});
    } else {
        global.hasQueryToken = true;
        global.tokenExpiredList = [{request, callback}];
        const refreshUrl = `${RNStorage.baseUrl}api/refreshToken?refreshToken=${RNStorage.refreshToken}`;
        fetch(refreshUrl).then(resp => {
            resp.json().then(({successful, data: {accessToken}}) => {
                if (successful === 1) {// 获取到新的accessToken
                    RNStorage.accessToken = accessToken;
                    global.tokenExpiredList.map(({request, callback}) => {
                        request.resendRequest(request, callback);
                    });
                    global.tokenExpiredList = [];
                } else {
                    console.log('Token 过期,退出登录');
                }
            });
        }).catch(err => {
            console.log('Token 过期,退出登录');
        }).finally(() => {
            global.hasQueryToken = false;
        });
    }
};

就这样对当前构想的app的逻辑层面的封装就实现了(实现上面的代码约70行,也许要超过20分钟 ??,但相较于以前从零开的封装,是不是节约了大量的时间呢?)是不是清晰明了。当然,这只是代码片段,没有实际操作,就没办法证明上面的代码实现是实际有效的。


为了演示,先用 react native init HttpTestDemo 创建一个RN项目:示例项目:HttpTestDemo 修改并删除不必要的布局或资源,结果如下:

假定有三个接口,分别为 api/login、api/userInfo 、api/refreshToken (为了省事,接口都以json文件替代

  • api/login 有两个必传参数:[userName、userPass];请求内容类型为:application/x-www-form-urlencoded;post请求
  • api/userInfo 无参数;请求内容类型为:application/json;get请求
  • api/refreshToken 必须参数refreshToken;请求内容类型为:application/json;get请求

https://react-native-easy-app.oss-cn-beijing.aliyuncs.com/api/login https://react-native-easy-app.oss-cn-beijing.aliyuncs.com/api/userInfo https://react-native-easy-app.oss-cn-beijing.aliyuncs.com/api/refreshToken

  1. react-native-easy-app 的说明文档,安装库:npm install react-native-easy-app --save
  2. 定义一个持久化对象,用于保存accessToken,customerId等参数:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export const RNStorage = {// 持久化数据列表
    customerId: undefined,//客户ID
    accessToken: undefined,//OAuth2.0 accessToken
    refreshToken: undefined,//OAuth2.0 refreshToken
    baseUrl: undefined,
    userInfo: undefined,
    hasLogin: false,
};

3.在页面的构造方法时调用 RNStorage的初始化操作;初始化完成之后,调用Http请求RFHttpConfig的【业务逻辑】层初始化方法,这样就完成了,现在就可以调用接口了。

  • 调用登录接口:(由于使用json文件的形式只能使用get请求)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { RFHttp } from 'react-native-easy-app';

login = () => {
    let params = {userName: 'zhangsan', userPass: '123456a'};
    RFHttp().url('api/login').param(params).formEncoded().get((success, json, message, status, resonse) => {
        if (success) {
            if (resonse.headers && resonse.headers.map) {
                RNStorage.accessToken = resonse.headers.map['x-oss-meta-accesstoken'];
                RNStorage.refreshToken = resonse.headers.map['x-oss-meta-refreshtoken'];
            }
            RNStorage.customerId = json.customerId;
            RNStorage.hasLogin = true;
            this.setState({data: JSON.stringify(json)});
        } else {
            console.log('失败', message);
        }
    });
};

调用接口,通过框架自带的日志功能,可以看到,该拼的参数都拼接了,从header中也获取到了token

  • 调用获取用户个人信息接口:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { RFHttp } from 'react-native-fast-app';

queryUserInfo = () => {
    RFHttp().url('api/userInfo').formJson().get((success, json, message) => {
        if (success) {
            RNStorage.userInfo = json;
            this.setState({data: JSON.stringify(json)});
        } else {
            console.log('失败', message);
        }
    });
};

调用接口,通过框架自带的日志功能,可以看到accessToken、refreshToken也正确的拼接了。

由于没有合适的服务器,token过期的情况就不演示了,只要请求refreshToken的接口正常请求就不会有问题。

至此一个完整的App 【业务逻辑】层面的封装就完全实现了,从Http请求的配置到,refreshToken的重新请求到刷新失败接口,一共大概只用了70行代码左右,是不是相较于之前从零开始的fetch封装简单容易多了,节约了大量的封装时间呢?

担心框架的灵活性?请参考 react-native-easy-app 详解与使用之(二) fetch 并且react-native-easy-app 开源库并不只有Http请求的封装,还有更多功能,有兴趣的同学可以查看此栏目的其它文章,你肯定会有更多收获。

当前示例项目链接:HttpTestDemo

有任何疑问,欢迎扫码加入RN技术QQ交流群

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
react-native-easy-app 详解与使用之(二) fetch
react-native-easy-app 是一款为React Native App快速开发提供基础服务的纯JS库(支持 IOS & Android),特别是在从0到1的项目搭建初期,至少可以为开发者减少30%的工作量。
rufeng008
2020/04/11
2.7K0
Go WEB进阶实战:基于GoFrame搭建的电商前后台API系统
最近有很多小伙伴私信我:在学完Go基础后,想使用一个框架实战一个商业项目,但是又苦于不知道选择什么框架,更不知道做什么商业项目。
王中阳Go
2022/10/26
1.4K0
Go WEB进阶实战:基于GoFrame搭建的电商前后台API系统
基于 Axios 封装一个完美的双 token 无感刷新
用户登录之后,会返回一个用户的标识,之后带上这个标识请求别的接口,就能识别出该用户。
神说要有光zxg
2023/08/28
1.5K0
基于 Axios 封装一个完美的双  token 无感刷新
react-native-easy-app 详解与使用之(一) AsyncStorage
react-native-easy-app 是一款为React Native App快速开发提供基础服务的纯JS库(支持 IOS & Android),特别是在从0到1的项目搭建初期,至少可以为开发者减少30%的工作量。
rufeng008
2020/04/11
1.7K0
Vue + Flask 小知识(六)
由于我们会有很多请求,都需要验证 token 的有效性,那么把这部分逻辑抽象出来就是最好的选择了。我这里大概想到了以下两种验证的方法
周萝卜
2019/07/30
8460
JWT双令牌认证实现无感Token自动续约
JSON Web Token (JWT)是一个开放标准(RFC 7519) ,它定义了一种紧凑和自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。此信息可以进行验证和信任,因为它是经过数字签名的。JWT 可以使用机密(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
Tinywan
2024/08/21
7470
JWT双令牌认证实现无感Token自动续约
前端 mock 完美解决方案实战
写在前面,本文阅读需要一定Nodejs的相关知识,因为会扩展webpack的相关功能,并且实现需要遵守一定约定和Ajax封装。
coder_koala
2020/12/17
2.3K0
Dva + Ant Design 前后端分离之 React 应用实践
继 Rails 从入门到完全放弃 拥抱 Elixir + Phoenix + React + Redux 这篇文章被喷之后,笔者很长一段时候没有上社区逛了。现在 tkvern 又回归了,给大家带来React实践的一些经验,一些踩坑的经验。
零式的天空
2022/03/23
2.7K0
JWT 的详细资源
1、laravel firebase/php-jwt token验证
八点半的Bruce、D
2023/02/28
3K0
JWT 的详细资源
【Go WEB进阶实战】开源的电商前后台API系统
最近有很多小伙伴私信我:在学完Go基础后,想使用一个框架实战一个商业项目,但是又苦于不知道选择什么框架,更不知道做什么商业项目。
王中阳Go
2023/01/08
8850
【Go WEB进阶实战】开源的电商前后台API系统
一个 Hybrid SDK 设计与实现
随着移动浪潮的兴起,各种 App 层出不穷,极速发展的业务拓展提升了团队对开发效率的要求,这个时候纯粹使用 Native 开发技术成本难免会更高一点。而 H5 的低成本、高效率、跨平台等特性马上被利用起来了,形成一种新的开发模式:Hybrid App
IT大咖说
2021/07/19
1.3K0
react-native-easy-app 详解与使用之(三) View,Text,Image,Flatlist
react-native-easy-app 是一款为React Native App快速开发提供基础服务的纯JS库(支持 IOS & Android),特别是在从0到1的项目搭建初期,至少可以为开发者减少30%的工作量。
rufeng008
2020/04/11
2.4K0
认证授权:JustAuth 简介及实践
JustAuth,如你所见,它仅仅是一个第三方授权登录的工具类库,它可以让我们脱离繁琐的第三方登录 SDK,让登录变得So easy!
Freedom123
2024/03/29
4720
看完就懂的Hybrid框架设计方案
本篇文章探讨“基于 Webview,如何在 App 内实现带离线包能力的 H5”。在当下这个主题似乎有些过时,但 H5 技术以其良好的跨端一致性,长期来看会占据一席之地,希望整理一个较完整的方案,从基本的实现原理到业务具体应用,让不了解的同学对“离线 H5"有一个较完整的视角。
腾讯云开发者
2024/04/12
2.5K0
看完就懂的Hybrid框架设计方案
axios详解以及完整封装方法
Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
HelloWorldZ
2024/03/20
10.5K0
前端构建 DevOps - 搭建 DevOps 基础平台(上)
在上一个博客中,已经通过 Egg 对 Gitlab Api 进行了基础的封装,本文将会围绕 DevOps 流程介绍项目设计(偏后台),需要读者具备一定的后端知识储备。
Cookieboty
2020/10/23
1.7K0
前端构建 DevOps - 搭建 DevOps 基础平台(上)
iOS电商类APP的研发
前言 本文是研发一个在线超市的电商类APP过程中,对架构的整理。 功能: 1、浏览商品、购买商品、切换商店; 2、查看订单、订单投诉、意见反馈; 3、登陆、退出、收货地址管理; 4、支付、取消订
落影
2018/04/27
2.7K1
iOS电商类APP的研发
Vue + Flask 小知识(七)
用户登陆系统之后,如果一段时间没有任何操作,session 需要有一个超时过期的动作,用户需要再次登陆才可以使用系统。
周萝卜
2019/08/26
1.1K0
Android笔记:集成原生微信授权获取用户信息登录
其实两年前做过这个功能,项目最近需要加上获取微信用户信息的需求,索性我就写成一篇文章,当做笔记 我在项目中用到的是点击一个按钮发起微信授权请求的需求,首先判断是否安装微信,如果安装微信则进行用户授权,授权成功之后通过微信提供的接口获取openID等用户信息,然后做自己的业务:
程思扬
2022/01/11
9340
深度解读-如何用keycloak管理external auth
简单来说,以google授权为例,一般就是通过用户授权页面登录google账号,再跳转用code换取到相应权限的token,就可以代表用户去发起一些google api的请求。
newbmiao
2023/11/27
8470
深度解读-如何用keycloak管理external auth
推荐阅读
相关推荐
react-native-easy-app 详解与使用之(二) fetch
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验