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

2018-08-20 10:26:58 浏览数 (1)

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

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

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

关于IDE插件的,可以查看我另一篇文章开发工具插件。

image.png

image.png

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

一、全局设置服务

ionic g provider config

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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>),但为了肉眼快速分辨出是异步方法还是普通方法?返回参数是什么类型?我习惯了书写。

晚了,先写到这里。

0 人点赞