阿里推送 NodeJS 给iOS及ANDROID 发推送。

本文介绍了如何使用NodeJS配合阿里移动推送服务为iOS和Android设备发送推送通知。开发者需要注意时间格式字段需去除毫秒,并正确生成接口所需的签名。通过封装类和方法,可以将十几个接口整合到一个通用方法中,简化调用过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其实阿里推送官网也有自己的sdk。可是他给的demo就一两个方法,其它的都就没有了。项目代码上传到我的 Gitlab aliyun_push上去了,感兴趣的可以下载试试,配置几个参数就可以使用了。

想了想还是自己按照他们的接口自己写重新写一套吧。

在写的过程当中,有个非常小心的地方,时间格式字段,由于没有看清楚,以为 new Date().toISOString();不OK了,那就错了。

new Date().toISOString() 出来的时间,是带毫秒的,他给出的接口里的是不带毫秒的。

第二个就是生成签名,这里要小心就是有一字符要进行转换要不能他就直说签名不正确,于是就封装了一个类。


export default class CommParamService {

  constructor() {
    this.__InitBaseParams();
  }

  /**
   * 基本参数
   *
   * @memberof CommParamService
   */
  __InitBaseParams() {
    this.ParamMap = {};
    //--公共参数部分。
    this.AddParam('Version', version);
    this.AddParam('Format', format);
    this.AddParam('AccessKeyId', accessKeyId);
    this.AddParam('SignatureMethod', signatureMethod);
    this.AddParam('SignatureVersion', signatureVersion);
    this.AddParam('SignatureNonce', Utility.generateSerNum());  // 随机数
    this.AddParam('Timestamp', new Date().toISOString());       // 时间截
  }

  /**
   * 添加参数
   *
   * @param {*} key
   * @param {*} value
   * @memberof CommParam
   */
  AddParam(key, value) {
    this.ParamMap[key] = value;
    return this;
  }

  /**
   * 参数
   *
   * @param {boolean} [isPop=false]
   * @returns
   * @memberof CommParam
   */
  QueryParams(isPop = false) {
    const map = this.ParamMap;
    const keys = Object.keys(map).sort();
    const keyValues = [];
    keys.forEach((key) => {
      const _value = !!isPop ? this.ConvertToEscape(map[key]) : encodeURIComponent(map[key]);
      keyValues.push(`${key}=${_value}`);
    });
    const qp = keyValues.join('&');
    return qp;
  }

  /**
   * 签名
   *
   * @memberof CommParam
   */
  Signature(Method = 'POST') {
    const privateParams = this.ConvertToEscape(this.QueryParams(true));
    const stringToSign = `${Method.toUpperCase()}&${encodeURIComponent('/')}&${privateParams}`;

    const sign = crypto.createHmac('sha1', `${secretAccessKey}&`.toString('utf-8'))
      .update(stringToSign.toString('utf-8'))
      .digest()
      .toString('base64');
    this.AddParam('Signature', sign);
    return sign;
  }

  /**
   * 值转换
   *
   * @param {*} value
   * @returns
   * @memberof CommParam
   */
  ConvertToEscape(value) {
    return encodeURIComponent(value)
      .replace(/\!/gi, '%21')
      .replace(/\'/gi, '%27')
      .replace(/\(/gi, '%28')
      .replace(/\)/gi, '%29')
      .replace(/\*/gi, '%2A');
  }
}

如果要调用怎么呢?在另一个AliyunService里写一个方法如给iOS推送。

export default class AliYunService {

  async __SendMsg({ cps, }) {
    cps.Signature();
    const urlParam = cps.QueryParams();
    Utility.printLog(cps.ParamMap, '\r\n', urlParam);
    const result = await HttpHelper.onApiPost(PushUrl, { data: urlParam, headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' } });
    return result;
  }

  /**
   * 推通知给iOS设备
   *
   * @returns
   * @memberof AliYunService
   */
  async PushNoticeToiOS(params = {}) {
    const cp = new CommParamService();
    cp.AddParam('Action', 'PushNoticeToiOS')
      .AddParam('ApnsEnv', apnsEnv || 'DEV')
      .AddParam('Target', 'ACCOUNT')                  // 指定帐号,用的是用户ID。
      .AddParam('TargetValue', 'user_account_id')
      .AddParam('Title', '测试通知标题')
      .AddParam('ExtParameters', JSON.stringify({ url: 'http://m.yfarm.net/#app/home' }))
      .AddParam('Body', `终于成功啦${Utility.formatDate(new Date().getTime())}`);
    return await this.__SendMsg({ cps: cp });
  }

} 

到这里阿里App的核心功能就基本上OK了。ios或android基本上就能接到推送消息了。

这里有个小小的问题,那就是十几个接口,能不能合到一个方法里来实现呢,参数是外面传进入你要调用哪个方法。

然后每个接口需要的参数与传的参数进行匹配上。合完之后方法代码如下:

/**
   * 发送推送
   *
   * @param {*} params
   * @returns
   * @memberof AliYunService
   */
  async SendPush(params) {
    const { Action } = params;
    const { Api } = this.AliPushApiMap();
    const { Input } = Api[Action];
    if (!Input) {
      Utility.throwClientError({ msg: `【${Action}】方法没有找到。` })
    }
    const cps = new CommParamService();
    cps.AddParam('Action', Action);
    const keys = Object.keys(Input);
    for (let i = 0; i < keys.length; i += 1) {
      const key = keys[i];
      const { Required, Type, Desc, Default } = Input[key];
      const _value = params[key];
      // Utility.printLog(key, _value, Default);
      if (Required) {
        if (Type === TypeMap.Boolean) {
          if (Utility.isBoolean(_value)) {
            cps.AddParam(key, _value);
          } else if (Utility.isBoolean(Default)) {
            cps.AddParam(key, Default);
          } else {
            Utility.throwClientError({ msg: `${key} 不能为空:${Desc}` });
          }
        } else if (Type === TypeMap.DateTimeByISO601) {
          if (!_value) {
            Utility.throwClientError({ msg: `${key} 不能为空:${Desc}` });
          } else {
            cps.AddParam(key, _value.toISOString().replace(/\.\d\d\d/g, ''));              // 去掉毫秒。
          }
        } else if (_value) {
          cps.AddParam(key, Type === TypeMap.Object ? JSON.stringify(_value) : _value);
        } else if (Default) {
          cps.AddParam(key, Type === TypeMap.Object ? JSON.stringify(Default) : Default);
        } else {
          Utility.throwClientError({ msg: `${key} 不能为空:${Desc}` });
        }
      } else {
        if (Type === TypeMap.Boolean) {
          if (Utility.isBoolean(Default)) {
            cps.AddParam(key, Default);
          }
        } else if (_value) {
          cps.AddParam(key, Type === TypeMap.Object ? JSON.stringify(_value) : _value);
        } else if (Default) {
          cps.AddParam(key, Type === TypeMap.Object ? JSON.stringify(Default) : Default);
        }
      }
    }
    return await this.__SendMsg({ cps });
  }

然后想调用哪个只要配置上就OK了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值