【Appetite】ionic3实录(五)基本服务实现

写了几节UI方面的内容,有点累了吧?这节先换点别的东西写。

前面章节基本把应用的总体配置完成了,开始进入具体页面的开发,而这些离不开与数据的交互、与用户的反馈操作等。正所谓“兵马未动,粮草先行”,现在封装下基本的服务。

前面章节我们都是用命令行来操作,如ionic g page person,现在开始会涉及到很多命令操作,可能有些人会记不住命令,或者记不清关键字,可以像我这样,在IDE上装上插件,我这用的是VS Code,装了插件后,src目录右键会出现Ionic Generate的快捷菜单,点击后弹出选择界面,输入名称即可自动创建。
关于IDE插件的,可以查看我另一篇文章开发工具插件

image.png

image.png

TypeScript中,public为默认访问级别,即外部可以访问的,所以如果想控制权限,请手动添加private关键字。常规应用,一般会有通用服务和具体业务服务,而常用的通用服务有如下几个:

一、全局设置服务

ionic g provider config

import { Injectable } from '@angular/core';
import { Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class ConfigProvider {

  constructor() {
  }

   /**
   * 获取域名
   * @param versionType 版本类型,0:正式环境,1:测试环境,2: 本地
   */
  static getDomainInfo(versionType: number = 1): any{
    let domain: string;
    switch(versionType){
      case 0: domain = "http://"; break;  //正式环境
      case 1: domain = "http://"; break;    //测试环境
      case 2: domain = ""; break;    //本地
      default: domain = ""; break;
    }
    return {domain: domain, versionType: versionType};
  }

  /**
   *获取api地址
   */
  static getApiHost(){
      return ConfigProvider.getDomainInfo().domain + "";
  }

  static defaultHeaders = new Headers({'Content-Type': 'application/json', 'Accept': 'application/json'});
  static formHeaders = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': 'application/json'});
  static uploadHeasers = new Headers({'Content-Type': 'multipart/form-data'});
  //
  static defaultOptions = new RequestOptions({headers: ConfigProvider.defaultHeaders});
  static formOptions = new RequestOptions({headers: ConfigProvider.formHeaders});
  static uploadOptions = new RequestOptions({headers: ConfigProvider.uploadHeasers});

}

因为有时需要在几个环境切换服务地址,所以写一个方法方便切换地址;
另外angular默认使用application/json的请求头,有时我们需要根据后台接口来配置请求头,在这就预先配置几个常用的RequestOption,方便按需要随时切换。

二、网络请求服务

ionic g provider common

import 'rxjs/add/operator/retry';
import 'rxjs/add/operator/timeout';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';

import { Headers, Http, RequestOptions } from '@angular/http';

import { ConfigProvider } from './config';
import { Injectable } from '@angular/core';

//处理过的响应数据
export interface IResponseData<T> {
  success: boolean;
  msg: string;
  code?: number;
  result?: T;      //响应数据
}

@Injectable()
export class CommonProvider {

  constructor(public authHttp: Http) {    
  }

  /**
   * get方法(isJoinHost是为了兼容获取应用内部数据)
   * @param url 请求url
   * @param isJoinHost 是否合并到主机地址
   */
  get(url: string, isJoinHost: boolean = true) {
    url = (isJoinHost && url.indexOf('http') <0) ?  ConfigProvider.getApiHost() + encodeURI(url) : encodeURI(url);
    return this.authHttp.get(url)
      .timeout(60000)
      .toPromise()
      .then(result => result.json())
      .catch(resp => this.handleHttpError(resp));
  }

  /**
   * post方法
   * @param url 请求url
   * @param data 请求参数
   * @param options 请求选项
   */
  post(url: string, data: any = {}, options: RequestOptions = ConfigProvider.formOptions) {
    url = url.indexOf('http') > -1 ? url : ConfigProvider.getApiHost() + url;
    return this.authHttp.post(url, data, options)
      .timeout(60000)
      .toPromise()
      .then(result => result.json())
      .catch(resp => this.handleHttpError(resp));
  }

 /**
 * 处理http错误
 */
  handleHttpError(resp): IResponseData<any> {
    let errMsg = '抱歉,后台服务出错了';
    if (resp) {
      let msg: string = resp.message;
      if (msg && msg.toLowerCase().indexOf('timeout') > -1) {
        errMsg = '请求超时,请稍后重试!';
      } else {
        switch (resp.status) {
          case 401: errMsg = '无权限访问,或许登录信息已过期,请重新登录';
          case 404: errMsg = '抱歉,后台服务找不到对应接口';
          case 0: errMsg = '网络无法连接';
          default: break;
        }
      }
    }
    return { success: false, msg: errMsg, code: -1, result: null};
  }
}

这里只简单的封装了带超时和错误处理的get、post方法。因为数据接口服务往往不会只返回数据,还应带有请求信息,如获取数据为空,可以提示是系统问题、权限问题还是数据本就这样,所以封装了统一响应数据接口。

因为目前大多插件的异步使用Promise,Observable转Promise比较简单,而Promise转Observable比较麻烦,为了更方便集成,所以把官方推荐的Observable方式转成Promise方式,大家可基于Observable优点考虑仍沿用Observable也行。

注意catch里面用了return,表示捕获了异常处理并返回,下次链式调用将进入then,这样每个调用网络请求后的逻辑操作可以全放在then里,省掉写catch的部分。要想下次链式调用再处理异常,就应用Promise.reject继续抛出异常。

三、权限服务

ionic g provider auth

先建个文件备用。

四、缓存服务

ionic g provider cache

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Storage } from '@ionic/storage';

/**
 * 用枚举管理key值,防止字符串拼错
 */
export enum CacheKeys {
  TOKEN, AUTO_LOGIN, USER_INFO
}

@Injectable()
export class CacheProvider {

  constructor(public http: Http, public storage: Storage) {
    console.log(CacheKeys[CacheKeys.TOKEN]);
  }
}

因为key使用字符串方式,不容易记忆使用,也容易敲错,为了便于管理Key,用枚举来处理。后续补充结合http的缓存请求。

五、工具服务

ionic g provider util

import 'rxjs/add/operator/map';
import { DomSanitizer } from '@angular/platform-browser';
import { Injectable } from '@angular/core';
/*
  工具类
  Generated class for the UtilProvider provider.
*/
@Injectable()
export class UtilProvider {

  constructor(private sanitizer: DomSanitizer) {
  }

 /**
   * 深拷贝
   */
  deepCopy(originObj: any): any{
    return originObj ? JSON.parse(JSON.stringify(originObj)) : null;
  }

  /**
   * 处理html的安全信任
   * @param html raw html
   */
  sanitizeHtml(html: string): any{
    return this.sanitizer.bypassSecurityTrustHtml(html);
  }
}

先实现两个应该要用到的方法,待后续实现功能时再扩展。

这些服务会随着业务功能的开发而补充,服务的每个方法可以不写返回类型(如fun: Promise<any>里的 Promise<any>),但为了肉眼快速分辨出是异步方法还是普通方法?返回参数是什么类型?我习惯了书写。

晚了,先写到这里。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容