热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

前端项目要求层封装历程

挪用ajax取要求后端数据是项目中最基础的功用。然则假如每次直接挪用底层的浏览器api去发要求则非常贫苦。如今来剖析一下怎样封装这一层,看看有哪些基础题目须要斟酌。本文底层运用fe

挪用 ajax 取要求后端数据是项目中最基础的功用。然则假如每次直接挪用底层的浏览器 api 去发要求则非常贫苦。如今来剖析一下怎样封装这一层,看看有哪些基础题目须要斟酌。本文底层运用 fetch ,假如你运用 XMLHttpRequest 以至第三方库(比如:axios)封装历程都是迥然不同的。

封装反复代码

关于同一个项目一般来讲要求参数有许多反复的内容,比如 url 的拼接,http head 的设置。假定我们挪用的是 RESTful 接口,一般我们须要更改的有:1. 要求 url 的 path 部份;2. 参数;3. 要求 method;4. 胜利/失利回调函数。我们看下把反复代码封装成一个 ApiSender 的示例代码:

const URL_PREFIX = 'xxx';
let ApiSender = {
send( options ) {
let {
path,
params,
method,
success,
fail
} = options;
let url = URL_PREFIX + path;
if ( method==='GET' ) {
url += ('?'+toQueryString( params ));
}
let requestBody;
if ( method==='POST' ) {
requestBody = params;
}
fetch( url, {
method: method,
// 这里假定我们项目要求头牢固这两个
headers: {
'Accept': 'application/json, text/Javascript, */*; q=0.01',
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
credentials: 'include',
body: requestBody
} ).then( function(response){
let resultJson = response.json();
if ( /* 推断返回没有毛病 */ ) {
success && success( resultJson );
} else {
fail && fail( resultJson.error );
}
} );
}
}

使挪用可读性更好

以上封装了一个 ApiSender,挪用的时刻以下:

ApiSender.send( '/resource', 'GET', {
pageSize: 10,
pageNo: 1
}, function( result ){
// 对效果举行处置惩罚
}, function( error ){
alert( error )
} )

经由过程传递回调函数的体式格局,可读性性不是很好(固然这是一个仁者见仁的题目)。我们把返回改成 Promise。由于我们用的是 fetch,它直接返回的就是 Promise,比较好改。假如你底层用的是 XMLHttpRequest,那末能够自行把挪用 XMLHttpRequest 的代码封装在一个 Promise 中返回。

let ApiSender = {
send( options ) {
let {
path,
params,
method,
success,
fail
} = options;
let url = URL_PREFIX + path;
if ( method==='GET' ) {
url += toQueryString( params );
}
let requestBody;
if ( method==='POST' ) {
requestBody = params;
}
return fetch( url, {
method: method,
// 这里假定我们项目要求头牢固这两个
headers: {
'Accept': 'application/json, text/Javascript, */*; q=0.01',
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
credentials: 'include',
body: requestBody
} ).then( function(response){
return response.json()
} );
}
}

挪用的时刻代码就变成:

ApiSender.send( '/resource', 'GET', {pageSize:10,pageNo:1} ).then( function(result){
if ( /* 推断返回没有毛病 */ ) {
// 处置惩罚效果
} else {
// 提醒毛病
}
} )

从挪用者角度笼统返回值

上面代码有一个题目,关于 ApiSend 的挪用者来讲,他须要直接处置惩罚接口返回值,推断是不是胜利。假如接口返回对象比较简单还好,假如非常庞杂,那末挪用者就很头疼,举个例子,我碰到过以下的接口返回值:

{
content: {
result: {
errorCode: 1,
errorMessage: '',
isSuccess: true
},
data: {}|[] // 真正的可用数据
},
a: { // 有特性的字段名我做了简化,运用了a,ab如许的字段名。a 这个字段内容是 api 网关层包装的。
code: 1,
ab: [ {
code: 1
} ]
}
}

怎样推断这个返回值是胜利的呢?

let result = { /* 上面谁人对象 */ }
if (
result.a &&
result.a.code === 0 &&
result.a.ab &&
result.a.ab[ 0 ] &&
result.a.ab[ 0 ].code === 0
) {
if (
result.content &&
result.content.result &&
result.content.result.isSuccess === true
) {
// 处置惩罚效果 result.content.data
}
}

你设想下,作为 ApiSender 的挪用方,会愿望取得什么效果?实行准确的时刻取得接口返回的数据,实行非常的时刻取得毛病信息。我不愿望挪用一个要领,须要经由过程庞杂地剖析返回值来推断是不是胜利。所以最直观的就是把毛病封装成一个很直观的返回值:

let ApiSender = {
send( options ) {
/* 代码省略掉了 */
return fetch( /* 参数也省略掉了 */ ).then( function(response){
let result = response.json();
if ( isSuccessResult(result) ) {
return [ null, result.content.data ]
} else {
let error = parseError( result );
return [ error, null ];
}
} );
}
}

那末挪用方对效果的推断就非常方便了:

ApiSender.send( '/resource', 'GET', {pageSize:10,pageNo:1} ).then( function([error,data]){
if ( !error ) {
// 处置惩罚效果 data
} else {
alert( error ); // error 的花样人人能够自行定义,各个项目各有不同
}
} );

面向切面须要做些什么

以上一个比较基础且简约的封装就做好了,然则实际中有些基础功用是常常须要的,比如要求日记,要求毛病报错一致处置惩罚。假如这些代码须要挪用方来做,一来代码反复,二来比如日记应该是挪用方不感知的一个功用。所以我们对代码进一步举行优化,到场这些功用:

let ApiSender = {
send( options ) {
/* 代码省略掉了 */
return fetch( /* 参数也省略掉了 */ ).then( function(response){
let result = response.json();
// 纪录挪用日记
writeLog( options, result );
if ( isSuccessResult(result) ) {
return [ null, result.content.data ]
} else {
let error = parseError( result );
// 界面报错
MessageComponent.error( `${error.message}(${error.code})` );
return [ error, null ];
}
} );
}
}

日记你能够上传服务器,也能够就当地 console,日记纪录哪些内容,参数怎样都按各自的项目需求而定。云云的话,挪用方就更简约了:

ApiSender.send( '/resource', 'GET', {pageSize:10,pageNo:1} ).then( function([error,data]){
if ( !error ) {
// 处置惩罚效果 data
}
} );

绝大多数状况下,挪用接口返回毛病是须要在页面上提醒毛病的,然则并非一切状况都须要。比如非用户触发的行动,且要求返回的效果并不严重影响页面操纵或许流程。那末我们能够在挪用 ApiSender 的时刻加一个参数,许可挪用方跳过全局毛病处置惩罚:

let ApiSender = {
send( options ) {
/* 代码省略掉了 */
let skipErrorHandler = options.skipErrorHandler;
return fetch( /* 参数也省略掉了 */ ).then( function(response){
let result = response.json();
// 纪录挪用日记
writeLog( options, result );
if ( isSuccessResult(result) ) {
return [ null, result.content.data ]
} else {
let error = parseError( result );
// 传了这个参数才跳过,不传或许传了非 true 值(固然包含 false),都以为不跳过
if ( skipErrorHandler===true ) {
// 界面报错
MessageComponent.error( `${error.message}(${error.code})` );
}

return [ error, null ];
}
} );
}
}

所以假如你愿望本身处置惩罚毛病,挪用的时刻代码就是:

ApiSender.send( '/resource', 'GET', {skipErrorHandler:true/*, 其他参数 */} ).then( function([error,data]){
if ( !error ) {
// 处置惩罚效果 data
} else {
// 自行处置惩罚毛病
}
} );

到这里为止,要求层的基础封装算是比较完整了,不过末了有一个小点要斟酌下,假如你在 fetch().then 传入的回调函数中由于种种原因而抛出了非常(比如某个字段没有判空)。那末 ApiSender 的挪用方是没法感知的,顺序直接就报错了。所以为了顺序的健壮性,我们末了再加一个 catch:

let ApiSender = {
send( options ) {
/* 代码省略掉了 */
let skipErrorHandler = options.skipErrorHandler;
return fetch( /* 参数也省略掉了 */ ).then( function(response){
let result = response.json();
// 纪录挪用日记
writeLog( options, result );
if ( isSuccessResult(result) ) {
return [ null, result.content.data ]
} else {
let error = parseError( result );
// 传了这个参数才跳过,不传或许传了非 true 值(固然包含 false),都以为不跳过
if ( skipErrorHandler===true ) {
// 界面报错
MessageComponent.error( `${error.message}(${error.code})` );
}

return [ error, null ];
}
} ).catch( function(error){
return [ error, null ];
} );
}
}

如许一个对挪用方友爱,防止代码反复的要求层就封装好了。PS: 假如对 Promise 的 api 不是很熟悉的话,能够先了解下,有助于更好的明白示例代码。


推荐阅读
  • 我有一个SpringRestController,它处理API调用的版本1。继承在SpringRestControllerpackagerest.v1;RestCon ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 本文探讨了在 SQL Server 中使用 JDBC 插入数据时遇到的问题。通过详细分析代码和数据库配置,提供了解决方案并解释了潜在的原因。 ... [详细]
  • Spring Boot 中静态资源映射详解
    本文深入探讨了 Spring Boot 如何简化 Web 应用中的静态资源管理,包括默认的静态资源映射规则、WebJars 的使用以及静态首页的处理方法。通过本文,您将了解如何高效地管理和引用静态资源。 ... [详细]
  • 本文详细介绍如何使用 Python 集成微信支付的三种主要方式:Native 支付、APP 支付和 JSAPI 支付。每种方式适用于不同的应用场景,如 PC 网站、移动端应用和公众号内支付等。 ... [详细]
  • 远程过程调用(RPC)是一种允许客户端通过网络请求服务器执行特定功能的技术。它简化了分布式系统的交互,使开发者可以像调用本地函数一样调用远程服务,并获得返回结果。本文将深入探讨RPC的工作原理、发展历程及其在现代技术中的应用。 ... [详细]
  • Java项目分层架构设计与实践
    本文探讨了Java项目中应用分层的最佳实践,不仅介绍了常见的三层架构(Controller、Service、DAO),还深入分析了各层的职责划分及优化建议。通过合理的分层设计,可以提高代码的可维护性、扩展性和团队协作效率。 ... [详细]
  • 深入理解Vue.js:从入门到精通
    本文详细介绍了Vue.js的基础知识、安装方法、核心概念及实战案例,帮助开发者全面掌握这一流行的前端框架。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • Python + Pytest 接口自动化测试中 Token 关联登录的实现方法
    本文将深入探讨 Python 和 Pytest 在接口自动化测试中如何实现 Token 关联登录,内容详尽、逻辑清晰,旨在帮助读者掌握这一关键技能。 ... [详细]
  • ssm框架整合及工程分层1.先创建一个新的project1.1配置pom.xml ... [详细]
  • SpringMVC RestTemplate的几种请求调用(转)
    SpringMVCRestTemplate的几种请求调用(转),Go语言社区,Golang程序员人脉社 ... [详细]
  • ListView简单使用
    先上效果:主要实现了Listview的绑定和点击事件。项目资源结构如下:先创建一个动物类,用来装载数据:Animal类如下:packagecom.example.simplelis ... [详细]
  • Django Token 认证详解与 HTTP 401、403 状态码的区别
    本文详细介绍了如何在 Django 中配置和使用 Token 认证,并解释了 HTTP 401 和 HTTP 403 状态码的区别。通过具体的代码示例,帮助开发者理解认证机制及权限控制。 ... [详细]
  • 本文探讨了如何在Java中使用JAXB解组两个具有相同名称但不同结构的对象。我们将介绍一个抽象类Bar及其具体实现,并展示如何正确地解析XML文档以获取正确的对象实例。 ... [详细]
author-avatar
mobiledu2502914997
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有