基于typeScript请求服务端的js-api-sdk统一封装思路
来源:互联网 发布:lamp源码安装包下载 编辑:程序博客网 时间:2024/05/17 08:15
项目地址
在前端开发中向服务端请求数据是非常重要的,特别是在复杂的项目中对后台的api接口进行友好的调用是非常重要的(这里不得不说typeScript写起代码的体验是很爽的)。
基本思路,可以想后台一样进行接口封装,比如用户相关的接口一个MemberServices 里面有关于用户所有的api接口 例如getMemberById等,这样尽量语义话的调用。
思路如下:
(1)首先抽象出一个Api请求的对象接口(抽象类)
/** * Api客户端请求接口 */export abstract class ApiClientInterface<T> { /** * 请求服务端client工具对象 * 非必填 */ private _client?: any; constructor(client: any) { this._client = client; } get client(): any { return this._client; } /** * post请求 * @param option */ post = (option: T): any => { } /** * get请求 * @param option */ get = (option: T): any => { } /** * 抓取数据 * @param option */ fetch = (option: T): any => { }}
其中这个泛型T是一个请求配置对象,可以根据不同的项目或者是实现进行切换,这里提供一个基于阿里weex开源项目中stream请求对象封装的 ApiClient和API配置对象的示例
/** * 请求服务端的api统一接口失效 */class ApiClient extends ApiClientInterface<WeexStreamOption> { /** * @param client WEEX 中的steam对象 */ constructor(client: any) { super(client); } /** * post请求 * */ post = (option: WeexStreamOption) => { option.method = ReqMethod.POST; return this.fetch(option); } /** * get请求 */ get = (option: WeexStreamOption) => { option.method = ReqMethod.GET; return this.fetch(option); } /** * 获取数据 * @param option * 默认 Content-Type 是 ‘application/x-www-form-urlencoded’。 * 如果你需要通过 POST json , 你需要将 Content-Type 设为 ‘application/json’。 */ fetch = (option: WeexStreamOption): any => { option.data = isUndefined(option.data) ? {} : option.data; const sign = this.sign(option.signFields, option.data); //获取签名字符串 if (option.method === ReqMethod.GET) { //拼接参数 let params = null; if (option.url.indexOf("?") > 0) { params = "&"; } else { params = "?"; } params += this.joinParamByReq(option.data); option.url += params; option.url += "&sign" + sign; } else if (option.method === ReqMethod.POST) { option.data['sign'] = sign; } console.log("请求url--> " + option.url); console.log("请求method--> " + option.method); console.log("请求headers--> " + option.headers); console.log("请求params--> " + JSON.stringify(option.data)); option.type = isUndefined(option.type) ? DataType.JSON : option.type; let num = Math.round(Math.random() * 20) let data = { isSuccess: num % 2 === 0, num: num }; option.progressCallback(data); setTimeout(function () { option.callBack(data); }, 1500) //WEEX stream对象 https://weex.apache.org/cn/references/modules/stream.html // this.client.fetch({ // method: ReqMethod[option.method], //请求方法get post // url: option.url, //请求url // type: DataType[option.type], //响应类型, json,text 或是 jsonp {在原生实现中其实与 json 相同) // headers: option.headers, //headers HTTP 请求头 // body: JSON.stringify(option.data) //参数仅支持 string 类型的参数,请勿直接传递 JSON,必须先将其转为字符串。请求不支持 body 方式传递参数,请使用 url 传参。 // }, function (response) { // console.log(response); // /** // * 响应结果回调,回调函数将收到如下的 response 对象: // * status {number}:返回的状态码 // * ok {boolean}:如果状态码在 200~299 之间就为真 // * statusText {string}:状态描述文本 // * data {Object | string}: 返回的数据,如果请求类型是 json 和 jsonp,则它就是一个 object ,如果不是,则它就是一个 string。 // * headers {Object}:响应头 // */ // if (!response.ok) { // //请求没有正确响应 // console.log("响应状态码:" + status + " 状态描述:" + response.statusText); // return; // } // option.callBack(response.data, response.headers); // }, function (resp) { // console.log(resp); // /** // * 关于请求状态的回调。 这个回调函数将在请求完成后就被调用: // * readyState {number}:当前状态state:’1’: 请求连接中opened:’2’: 返回响应头中received:’3’: 正在加载返回数据 // * status {number}:响应状态码. // * length {number}:已经接受到的数据长度. 你可以从响应头中获取总长度 // * statusText {string}:状态文本 // * headers {Object}:响应头 // */ // // if (option.progressCallback === null) { // return; // } // option.progressCallback(resp); // }); } /** * 将一个对象转换成url参数字符串 * @param req * @return {string} */ private joinParamByReq(req: Object): String { var result = ""; for (let key in req) { result += key + "=" + req[key] + "&"; } result = result.substr(0, result.length - 1); return result; } /** * ap请求时签名 * @param fields * @param params * @return {string} */ private sign = (fields: Array<String>, params: Object): String => { if (isUndefined(fields) || isNull(fields)) { return ""; } let value = ""; fields.forEach(function (item) { let param = params[item.toString()]; if (isUndefined(param)) { // console.warn("参与签名的参数:" + item + " 未传入!"); throw new Error("参与签名的参数:" + item + " 未传入!"); } value += item + "=" + param + "&"; }); value = "timestamp=" + params['timestamp']; //加入时间戳参与签名 let sign = md5(value); return sign; }}export default ApiClient;
/** * weex stream请求参数对象 */export interface WeexStreamOption { /** * 请求url */ url?: String; /** * 请求方法 */ method?: ReqMethod; /** * 结果数据类型 */ type?: DataType; /** * 请求头 */ headers?: Object; /** * 请求参数,仅post请求需要 */ data?: Object; /** * 参与签名的参数列表 */ signFields?:Array<String>; /** * 响应回调 */ callBack?:Function; /** * 关于请求状态的回调。 这个回调函数将在请求完成后就被调用: */ progressCallback?:Function;}
(2) 提供一个统一的实现,减少工作量,比起前端不是后端,不可能每一个接口都去实现一次,而且接口的流程非常统一,都是获取数据,只不过是url不同,参数不同,结果处理不同罢了。(这边实现使用Proxy对象)
抽象一个ServiceProxy对象
import ApiClient from "../ApiClient";import {isUndefined} from "util";import {DataType} from "./DataType";import {ReqMethod} from "./ReqMethod";/** * 服务代理 */export default class ServiceProxy { /** * * @param client 用于请求数据的客户端对象,非必填 * @param handler 接口对象 * @return {ServiceProxy} 返回代理对象 */ constructor(client: any = null) { const api = new ApiClient(client); const handler = this; console.log(handler); console.log(api) return new Proxy({}, { get: function (target, key, receiver) { return function () { let params = arguments[0]; let options = arguments[1]; let methodName = arguments[2].toUpperCase(); //请求方法 let resultDataType = arguments[3].toUpperCase(); //结果数据类型 return new Promise(function (resove, reject) { let config = handler[key](); //获取配置 if (isUndefined(config)) { throw new Error("请求的方法: " + key.toString() + " 未定义"); } options.url = config.url; //请求的url options.signFields = config.signFields; //参与签名的请求参数 options.method = isUndefined(methodName) ? config.method : ReqMethod[methodName]; //请求方法 post、get options.type = isUndefined(resultDataType) ? DataType.JSON : DataType[resultDataType]; //结果数类型 options.callBack = function (data) { console.log("api接口" + config.url + " 返回数据-> " + data); if (data.isSuccess) { resove(data); } else { reject(data) } }; options.data=params; let method = ReqMethod[options.method]; console.log(options); api[method.toLowerCase()](options); }); }; }, set: function (target, key, value, receiver) { throw new Error("接口不允许设置值!"); } }); }}(3)剩下的就是写具体的实现了,示例如下:
import ServiceProxy from “./api/base/ServiceProxy”;
import ApiConfig from “./api/base/ApiConfig”;
import {WeexStreamOption} from “./api/WeexStreamOption”;
import {TestReq} from “./TestReq”;
/**
* 测试服务接口
*/
export default class TestService extends ServiceProxy {
constructor(client?: any) { super(client);}/** * 该方法写法固定,可以考虑使用自动生成 * @param params 请求参数 * @param option 请求配置 * @param method 请求类型 * @param dataType 结果数据类型 * @return {ApiConfig} */testApi(params: TestReq, option: WeexStreamOption = {}, method?: String, dataType?: String): any { return ApiConfig.newInstance("/api/test.htm", ["userName", "phoneCode"]);};
}
服务中的方法实现非常统一,只是方法名和放回的ApiConfig对象中的数据不一样。这样实现以后对于服务调用就非常清晰了。
更多细节可以参考代码,项目地址在文章开头。
- 基于typeScript请求服务端的js-api-sdk统一封装思路
- 基于typeScript请求服务端的js-api-sdk 这种filter
- iOS 基于AF网络请求封装的简易思路
- webrtc封装sdk 思路
- 网络请求组件的封装思路
- Retrofit2 封装统一请求参数
- 封装网络请求库,统一处理通用异常 (基于volley网络请求库)
- 基于Laravel的API服务端架构代码
- 基于现有游戏服务端(java)的数据框架调整思路
- Web API 实战之 统一的请求验证
- Web API 实战之 统一的请求验证
- 在RemObjects SDK的服务端捕获客户端请求
- 基于AFNetWoring 封装的网络请求类
- 基于网络请求框架的封装
- Android--okhttp框架封装思路/网络请求组件的创建
- C++封装的基于WinSock2的TCP服务端、客户端
- 调用第三方服务API的SDK编写思路
- 基于LeanCloud平台的REST API封装
- CCF NOI1070 汉诺塔游戏
- 将SPSS中字符串格式的数据转化成日期格式
- Android面试题-Volley源码分析
- JSON for java入门总结
- spring的context:property-placeholder属性
- 基于typeScript请求服务端的js-api-sdk统一封装思路
- 如何评估当前数据库undo空间是否足够?
- PHP自动加载 spl_autoload_register
- Codeforces Round #383 (Div. 2) B. Arpa’s obvious problem and Mehrdad’s terrible solution 数学
- yii 增删改查 crud
- MindManager新手入门教程
- Python 内置函数 locals() 和globals()
- Java 内部类(Inner class)
- expat win10+vs2015编译