支付宝微信支付全本地写法和与服务器沟通方法

首先集成支付宝,微信,申请各自该申请的东西。这里不重复

主要包含以下东西:
主要包含的内容有这些

XZLPayBusiness要导入的头文件包含以下内容
要导入的头文件

1.支付宝全本地支付

+ (void)doAPPay:(NSString *)money {

    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"2048"ofType:@"txt"]; //这个文件里面就是支付宝的私钥
    NSString *rsa2PrivateKey = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];

    APOrderInfo* order = [APOrderInfo new];//这个类是直接用的支付宝Demo里的APOrderInfo,没有改,下面也有附上它的代码
    order.app_id = @"2018XXXXXXXXXXXXX"; // 写的是支付宝申请的appID,
    order.method = @"alipay.trade.app.pay";
    order.charset = @"utf-8";
    NSDateFormatter* formatter = [NSDateFormatter new];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    order.timestamp = [formatter stringFromDate:[NSDate date]];
    order.version = @"1.0";
    order.sign_type = @"RSA2";//我用的是RSA2加密方式,所以写RSA2
    order.notify_url = @"https://www.alipay.com";//这个我没有,有也可以写自己的(支付宝的结果会告诉这个接口)
    order.biz_content = [APBizContent new]; //这个也是直接从支付宝Demo拿过来的
    order.biz_content.body = @"三季度净亏损";
    order.biz_content.subject = @"健康管家";//这个名字支付的时候会显示出来的
    order.biz_content.out_trade_no = [self generateTradeNO]; //订单ID(由商家自行制定)
    order.biz_content.timeout_express = @"30m"; //超时时间设置
    order.biz_content.total_amount = [NSString stringWithFormat:@"%.2f", 0.01]; //商品价格 1分钱,支付宝和微信的单位不一样,下面有微信的

    NSString *orderInfo = [order orderInfoEncoded:NO];
    NSString *orderInfoEncoded = [order orderInfoEncoded:YES];
    NSString *signedString = nil;
    APRSASigner* signer = [[APRSASigner alloc] initWithPrivateKey:rsa2PrivateKey];
    signedString = [signer signString:orderInfo withRSA2:YES];

    if (signedString != nil) {
        NSString *appScheme = @"xxxxxxx";//写在info.plist加上的appScheme(是别的app跳到我们这个app的appScheme)
        NSString *orderString = [NSString stringWithFormat:@"%@&sign=%@",
                                 orderInfoEncoded, signedString];
        [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
            NSLog(@"reslut = %@",resultDic);//这个地方网页支付的时候会返回结果,
        }];
    }
}

辅助方法:
生成随机订单方法:

+ (NSString *)generateTradeNO
{
    static int kNumber = 15;
    NSString *sourceStr = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    NSMutableString *resultStr = [[NSMutableString alloc] init];
    srand((unsigned)time(0));
    for (int i = 0; i < kNumber; i++)
    {
        unsigned index = rand() % [sourceStr length];
        NSString *oneStr = [sourceStr substringWithRange:NSMakeRange(index, 1)];
        [resultStr appendString:oneStr];
    }
    return resultStr;
}

此外还需要在appDelegate写上如下代码,以知道支付完成返回的结果
appDelegate中倒入头文件:

#import <AlipaySDK/AlipaySDK.h>
#import "WXApiManager.h"
#pragma mark - -->(0)application:openURL:
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {

    if ([url.host isEqualToString:@"safepay"]) {
        // 支付跳转支付宝钱包进行支付,处理支付结果
        [self handleResultAlipayURL:url];
    }
    [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]]; // 这个是微信的,一并在这里写了

    return YES;
}

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

    if ([url.host isEqualToString:@"safepay"]) {
        [self handleResultAlipayURL:url];
    }

    [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
    return YES;
}

- (void)handleResultAlipayURL:(NSURL *)url {

     __block BOOL isSuccess = NO;
    // 支付跳转支付宝钱包进行支付,处理支付结果
    [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
        NSLog(@"result = %@",resultDic);
        NSString *strMeg = @"支付失败";
        if ([resultDic[@"resultStatus"] isEqualToString:@"9000"]) {
            strMeg = @"支付成功";
        }
    }];
}

2.微信全本地支付

+ (void)WXAppPay:(NSString *)body money:(NSString *)money {

    APWXOrderInfo* order = [APWXOrderInfo new];

    order.appid = WXAPPID;
    order.body = @"App pay test";
    order.mch_id = WXMCHID; //商户ID,自行申请
    order.nonce_str = [self generateTradeNO]; //生成随机订单方法,上面已写
    order.notify_url = @"http://www.weixin.qq.com";
    order.out_trade_no = [self getRandomString];
    order.spbill_create_ip = [self deviceIPAdress];
    order.total_fee = @"1";
    order.total_fee = [NSString stringWithFormat:@"%d",(int)([money floatValue] * 100)];
    order.trade_type = @"APP";

    NSString *orderInfo = [order orderInfoEncoded:NO];
    NSString *stringSignTemp = [NSString stringWithFormat:@"%@&key=%@",
                             orderInfo, WXKey];
    NSString *sign = [self md5:stringSignTemp];

    order.sign = sign;

    NSString *xmlStr = [order XMLStr];

    [self POST:@"https://api.mch.weixin.qq.com/pay/unifiedorder" params:xmlStr success:^(id responseObject) {

        NSDictionary *dict = [NSDictionary dictionaryWithXMLData:responseObject];

        if ([dict[@"return_code"] isEqualToString:@"SUCCESS"]) {

            if ([dict[@"result_code"] isEqualToString:@"SUCCESS"]) {

                //调起微信支付
                PayReq* req             = [[PayReq alloc] init];

                req.partnerId           = WXMCHID;
                req.prepayId            = [dict objectForKey:@"prepay_id"];
                req.package             = @"Sign=WXPay";
                req.nonceStr            = [dict objectForKey:@"nonce_str"];
                req.timeStamp           = [[NSString stringWithFormat:@"%.0f",[[NSDate date] timeIntervalSince1970]] intValue];

                NSString *orderInfo = [self partnerSignOrder:req];
                NSString *stringSignTemp = [NSString stringWithFormat:@"%@&key=%@",
                                            orderInfo, WXKey];
                NSString *sign = [self md5:stringSignTemp];

                req.sign                = sign;
                BOOL success = [WXApi sendReq:req];
                if (!success) {
                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"启动微信失败" message:@"请检查微信是否安装" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
                    [alert show];
                }
            } else {

                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"下单失败" message:dict[@"err_code_des"] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
                [alert show];
            }

        } else {

            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"下单失败" message:dict[@"return_msg"] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alert show];
        }

    } failure:^(NSHTTPURLResponse *httpResponse, NSError *error) {

    }];
}

辅助方法:

+ (NSString *)getRandomString
{
    NSString *str = [NSString stringWithFormat:@"%s",genRandomString(32)];
    return str;
}

char* genRandomString(int length)
{
    int flag, i;
    char* string;
    srand((unsigned) time(NULL ));
    if ((string = (char*) malloc(length)) == NULL )
    {
        //NSLog(@"Malloc failed!flag:14\n");
        return NULL ;
    }

    for (i = 0; i < length - 1; i++)
    {
        flag = rand() % 3;
        switch (flag)
        {
            case 0:
                string[i] = 'A' + rand() % 26;
                break;
            case 1:
                string[i] = 'a' + rand() % 26;
                break;
            case 2:
                string[i] = '0' + rand() % 10;
                break;
            default:
                string[i] = 'x';
                break;
        }
    }
    string[length - 1] = '\0';
    return string;
}

+ (NSString *)deviceIPAdress {

    NSString *address = @"an error occurred when obtaining ip address";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = 0;

    success = getifaddrs(&interfaces);

    if (success == 0) { // 0 表示获取成功

        temp_addr = interfaces;
        while (temp_addr != NULL) {
            if( temp_addr->ifa_addr->sa_family == AF_INET) {
                // Check if interface is en0 which is the wifi connection on the iPhone
                if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
                    // Get NSString from C String
                    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
                }
            }

            temp_addr = temp_addr->ifa_next;
        }
    }

    freeifaddrs(interfaces);
    return address;
}
+ (NSString *)md5:(NSString *)string{
    const char *cStr = [string UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];

    CC_MD5(cStr, (CC_LONG)strlen(cStr), digest);

    NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [result appendFormat:@"%02X", digest[i]];
    }

    return result;
}

+ (void)POST:(NSString *)urlString
      params:(NSString *)params
     success:(successBlock)success
     failure:(failureBlock)failure
{

    // 调用微信"统一下单"API
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.mch.weixin.qq.com/pay/unifiedorder"]];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
    [request setValue:@"text/plain" forHTTPHeaderField:@"content-type"];

    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

    if (success) {
        success(returnData);
    }
}
+ (NSString *)partnerSignOrder:(PayReq *)req {

    // NOTE: 增加不变部分数据
    NSMutableDictionary *tmpDict = [NSMutableDictionary new];
    [tmpDict addEntriesFromDictionary:@{@"appid":WXAPPID,
                                        @"noncestr":req.nonceStr,
                                        @"package":req.package,
                                        @"partnerid":req.partnerId,
                                        @"prepayid":req.prepayId,
                                        @"timestamp":[NSString stringWithFormat:@"%u",(unsigned int)req.timeStamp],
                                        }];

    // NOTE: 排序,得出最终请求字串
    NSArray* sortedKeyArray = [[tmpDict allKeys] sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        return [obj1 compare:obj2];
    }];

    NSMutableArray *tmpArray = [NSMutableArray new];
    for (NSString* key in sortedKeyArray) {
        NSString* orderItem = [self orderItemWithKey:key andValue:[tmpDict objectForKey:key] encoded:NO];
        if (orderItem.length > 0) {
            [tmpArray addObject:orderItem];
        }
    }
    return [tmpArray componentsJoinedByString:@"&"];
}

APWXOrderInfo.h

@interface APWXOrderInfo : NSObject

// NOTE: 支付宝分配给开发者的应用ID(如2014072300007148)
@property (nonatomic, copy) NSString *appid;

// NOTE: 商品描述
@property (nonatomic, copy) NSString *body;

// NOTE: 商户号
@property (nonatomic, copy) NSString *mch_id;

// NOTE: 随机字符串
@property (nonatomic, copy) NSString *nonce_str;

// NOTE: 支付宝服务器主动通知商户服务器里指定的页面http路径(本Demo仅做展示所用,商户需要配置这个参数)
@property (nonatomic, copy) NSString *notify_url;

// NOTE: 商户订单号
@property (nonatomic, copy) NSString *out_trade_no;

// NOTE: 终端IP
@property (nonatomic, copy) NSString *spbill_create_ip;

// NOTE: 总金额
@property (nonatomic, copy) NSString *total_fee;

// NOTE: 交易类型
@property (nonatomic, copy) NSString *trade_type;


// NOTE: 签名
@property (nonatomic, copy) NSString *sign;

// NOTE: (非必填项)签名类型
@property (nonatomic, copy) NSString *sign_type;

 // NOTE: (非必填项)设备号
 @property (nonatomic, copy) NSString *device_info;

// NOTE: (非必填项)商品详情
@property (nonatomic, copy) NSString *detail;

// NOTE: (非必填项)附加数据
@property (nonatomic, copy) NSString *attach;

// NOTE: (非必填项)货币类型
@property (nonatomic, copy) NSString *fee_type

// NOTE: (非必填项)交易起始时间
@property (nonatomic, copy) NSString *time_start;

// NOTE: (非必填项)交易结束时间
@property (nonatomic, copy) NSString *time_expire;

// NOTE: (非必填项)订单优惠标记
@property (nonatomic, copy) NSString *goods_tag;

// NOTE: (非必填项)指定支付方式
@property (nonatomic, copy) NSString *limit_pay;

// NOTE: (非必填项)场景信息
@property (nonatomic, copy) NSString *scene_info;

/**
 *  获取订单信息串
 *
 *  @param bEncoded       订单信息串中的各个value是否encode
 *                        非encode订单信息串,用于生成签名
 *                        encode订单信息串 + 签名,用于最终的支付请求订单信息串
 */
- (NSString *)orderInfoEncoded:(BOOL)bEncoded;

- (NSString *)XMLStr;

@end

APWXOrderInfo.m

@implementation APWXOrderInfo

- (NSString *)orderInfoEncoded:(BOOL)bEncoded {

    if (_appid.length <= 0) {
        return nil;
    }

    // NOTE: 增加不变部分数据
    NSMutableDictionary *tmpDict = [NSMutableDictionary new];
    [tmpDict addEntriesFromDictionary:@{@"appid":_appid,
                                        @"body":_body,
                                        @"mch_id":_mch_id,
                                        @"nonce_str":_nonce_str,
                                        @"notify_url":_notify_url,
                                        @"out_trade_no":_out_trade_no,
                                        @"spbill_create_ip":_spbill_create_ip,
                                        @"total_fee":_total_fee,
                                        @"trade_type":_trade_type,
                                        }];

    if (_device_info.length > 0) {
        [tmpDict setObject:_device_info forKey:@"device_info"];
    }

    if (_sign_type.length > 0) {
        [tmpDict setObject:_sign_type forKey:@"sign_type"];
    }

    if (_detail.length > 0) {
        [tmpDict setObject:_detail forKey:@"detail"];
    }

    if (_attach.length > 0) {
        [tmpDict setObject:_attach forKey:@"attach"];
    }

    if (_fee_type.length > 0) {
        [tmpDict setObject:_fee_type forKey:@"fee_type"];
    }

    if (_time_start.length > 0) {
        [tmpDict setObject:_time_start forKey:@"time_start"];
    }

    if (_time_expire.length > 0) {
        [tmpDict setObject:_time_expire forKey:@"time_expire"];
    }

    if (_goods_tag.length > 0) {
        [tmpDict setObject:_goods_tag forKey:@"goods_tag"];
    }

    if (_limit_pay.length > 0) {
        [tmpDict setObject:_limit_pay forKey:@"limit_pay"];
    }

    if (_scene_info.length > 0) {
        [tmpDict setObject:_scene_info forKey:@"scene_info"];
    }

    // NOTE: 排序,得出最终请求字串
    NSArray* sortedKeyArray = [[tmpDict allKeys] sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        return [obj1 compare:obj2];
    }];

    NSMutableArray *tmpArray = [NSMutableArray new];
    for (NSString* key in sortedKeyArray) {
        NSString* orderItem = [self orderItemWithKey:key andValue:[tmpDict objectForKey:key] encoded:bEncoded];
        if (orderItem.length > 0) {
            [tmpArray addObject:orderItem];
        }
    }
    return [tmpArray componentsJoinedByString:@"&"];
}

- (NSString *)XMLStr {

    if (_appid.length <= 0) {
        return nil;
    }

    NSMutableString *str = [[NSMutableString alloc] init];
    [str appendString:@"<xml>"];

    [str appendString:[NSString stringWithFormat:@"<appid>%@</appid>",_appid]];

    [str appendString:[NSString stringWithFormat:@"<body>%@</body>",_body]];

    if (_attach.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<attach>%@</attach>",_attach]];
    }
    if (_detail.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<detail>%@</detail>",_detail]];
    }
    if (_device_info.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<device_info>%@</device_info>",_device_info]];
    }

    if (_fee_type.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<fee_type>%@</fee_type>",_fee_type]];
    }

    if (_goods_tag.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<goods_tag>%@</goods_tag>",_goods_tag]];
    }

    if (_limit_pay.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<limit_pay>%@</limit_pay>",_limit_pay]];
    }

    [str appendString:[NSString stringWithFormat:@"<mch_id>%@</mch_id>",_mch_id]];

    [str appendString:[NSString stringWithFormat:@"<nonce_str>%@</nonce_str>",_nonce_str]];

    [str appendString:[NSString stringWithFormat:@"<notify_url>%@</notify_url>",_notify_url]];

    [str appendString:[NSString stringWithFormat:@"<out_trade_no>%@</out_trade_no>",_out_trade_no]];


    if (_scene_info.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<scene_info>%@</scene_info>",_scene_info]];
    }

    if (_sign_type.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<sign_type>%@</sign_type>",_sign_type]];
    }

    [str appendString:[NSString stringWithFormat:@"<spbill_create_ip>%@</spbill_create_ip>",_spbill_create_ip]];

    if (_time_expire.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<time_expire>%@</time_expire>",_time_expire]];
    }
    if (_time_start.length > 0) {
        [str appendString:[NSString stringWithFormat:@"<time_start>%@</time_start>",_time_start]];
    }

    [str appendString:[NSString stringWithFormat:@"<total_fee>%@</total_fee>",_total_fee]];

    [str appendString:[NSString stringWithFormat:@"<trade_type>%@</trade_type>",_trade_type]];

    [str appendString:[NSString stringWithFormat:@"<sign>%@</sign>",_sign]];

    [str appendString:@"</xml>"];

    return str;
}

- (NSString*)orderItemWithKey:(NSString*)key andValue:(NSString*)value encoded:(BOOL)bEncoded
{
    if (key.length > 0 && value.length > 0) {
        if (bEncoded) {
            value = [self encodeValue:value];
        }
        return [NSString stringWithFormat:@"%@=%@", key, value];
    }
    return nil;
}

- (NSString*)encodeValue:(NSString*)value {

    return getUrlEncodeStr(value);

    NSString* encodedValue = value;
    if (value.length > 0) {                                                            //!*'();:@&=+$,   #[]
        NSCharacterSet *charset = [[NSCharacterSet characterSetWithCharactersInString:@"!*'();:@&=+$,/?%#[]"]invertedSet];
        encodedValue = [value stringByAddingPercentEncodingWithAllowedCharacters:charset];
    }
    return encodedValue;
}
@end

在APPDelegate里的内容见1.支付宝全本地支付的AppDelagate里面的内容:结果解析见WXApiManager文件里面的- (void)onResp:(BaseResp *)resp方法,在那个方法里分析结果

3.支付宝与服务器沟通方法

+ (void)WXAppPay:(XZLPayOrderReq *)req {

    [self getPayOrderWithReq:req success:^(DQNetWorkResult *networkResult) { // 这个是个网络请求方法,写你们的请求就可以,req写你们的要求字段

        if ([networkResult.status isEqualToString:@"success"]) {

            XZLPayOrderRes *payOrderRes = networkResult.result.lastObject;

            //调起微信支付
            PayReq* req             = [[PayReq alloc] init];
            req.partnerId           = payOrderRes.partnerId;
            req.prepayId            = payOrderRes.prepayId;
            req.package             = payOrderRes.packageStr;
            req.nonceStr            = payOrderRes.noncestr;
            req.timeStamp           = [payOrderRes.timestamp intValue];
            req.sign                = payOrderRes.sign;
            NSTimeInterval timeInter = [[NSDate date] timeIntervalSince1970];
            NSString *timeStr = [NSString stringWithFormat:@"%.0f",timeInter];

            BOOL success = [WXApi sendReq:req];
            if (!success) {
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"启动微信失败" message:@"请检查微信是否安装" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
                [alert show];
            }
        } else {

            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"下单失败" message:networkResult.message delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alert show];
        }
    } failure:^(NSString *error) {

        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"下单失败" message:error.description delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];
    }];

}

4.支付宝与服务器沟通

“`
[self getPayOrderWithReq:req success:^(DQNetWorkResult *networkResult) {

    if ([networkResult.status isEqualToString:@"success"]) {

        XZLPayOrderRes *payOrderRes = networkResult.result.lastObject;
        NSString *appScheme = @"xxxxxxxx";
        [[AlipaySDK defaultService] payOrder:payOrderRes.orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
            NSLog(@"reslut = %@",resultDic);
        }];

    } else {

        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"下单失败" message:networkResult.message delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];
    }
} failure:^(NSString *error) {

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"下单失败" message:error.description delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [alert show];
}];```

如果有任何我写的不明白或错的地方,欢迎评论

<think> 我们正在处理的问题是:支付宝小程序提示 `errMsg: "onUnhandledRejection:ok"` 的解决方案。 根据错误信息,`onUnhandledRejection` 表示有未捕获的 Promise 拒绝(即未被 catch 的 Promise 错误)。该错误通常是由于代码中存在未处理的 Promise 异常导致。 解决方案步骤: 1. **定位错误来源**: - 在支付宝小程序开发者工具中,打开调试器,查看控制台(Console)是否有更详细的错误堆栈信息。 - 错误堆栈会指示出发生问题的代码位置。 2. **检查代码中未处理的 Promise**: - 查找代码中所有的 `Promise` 使用,确保每个 `Promise` 都带有 `.catch()` 处理。 - 特别注意 `async/await` 函数,虽然它们是基于 Promise 的,但错误需要通过 `try/catch` 捕获。 3. **全局捕获未处理的 Promise 拒绝**: - 在支付宝小程序中,可以通过在 `app.js` 中监听 `onUnhandledRejection` 事件来全局捕获未处理的 Promise 拒绝事件。 - 示例代码: ```javascript // app.js App({ onLaunch() {}, onUnhandledRejection: function (res) { console.error('未处理的 Promise 拒绝:', res.reason); // 这里可以上报错误日志 } }); ``` 通过这个全局事件,我们可以获取到导致拒绝的原因(`res.reason`),从而定位问题。 4. **使用 Promise 时显式捕获错误**: - 对于每个 `Promise` 调用,尽量添加 `catch`: ```javascript someAsyncFunction() .then(res => { ... }) .catch(err => { console.error('捕获到异步错误:', err); // 处理错误 }); ``` - 对于 `async/await`,使用 `try/catch`: ```javascript async function fetchData() { try { const res = await someAsyncFunction(); // ... 处理结果 } catch (err) { console.error('捕获到异步错误:', err); // 处理错误 } } ``` 5. **检查第三方库或插件**: - 如果使用了第三方库,确保这些库的异步操作也正确处理了错误。如果库本身没有捕获,则需要在调用时添加错误处理。 6. **测试覆盖**: - 在修复后,模拟错误场景,确保错误被正确处理,不会再触发 `onUnhandledRejection`。 7. **日志上报**: - 为了在生产环境中监控此类问题,建议在 `onUnhandledRejection` 事件中上报错误信息到服务器。 预防措施: - 在代码规范中,要求每个异步操作都必须有错误处理。 - 使用 ESLint 规则 `@typescript-eslint/no-floating-promises`(TypeScript)或 `no-unhandled-promises` 来避免未处理的 Promise。 相关问题: 1. 如何在小程序中进行错误监控? 2. 支付宝小程序中还有哪些常见的运行时错误? 3. 如何优化小程序中的异步代码以避免未处理的拒绝? 4. 如何在微信小程序中处理类似的未处理的 Promise 拒绝? 通过以上步骤,我们可以解决并预防 `onUnhandledRejection` 错误。如果问题仍然存在,请根据全局事件监听中捕获的错误信息进一步排查。 </think> ### 支付宝小程序 `errMsg: "onUnhandledRejection:ok"` 解决方案 #### 错误原因解析 该错误表示小程序中存在**未处理的 Promise 拒绝(Promise rejection)**。核心原因: 1. **异步操作未捕获异常**:`async/await` 或 `Promise` 未添加 `catch` 处理 2. **网络请求异常**:`my.request` 等接口调用失败未处理 3. **API 调用错误**:小程序 API 返回异常状态未处理 4. **全局 Promise 拒绝**:未被 `try/catch` 覆盖的异步操作错误 > 支付宝小程序在 `v2.x` 后强化了 Promise 错误处理机制[^1],未捕获的拒绝会触发此事件 --- ### 解决方案步骤 #### 1. 定位错误源 在小程序入口文件 `app.js` 添加全局监听: ```javascript // app.js App({ onUnhandledRejection(e) { console.error("未处理的Promise拒绝:", e.reason) my.showToast({ title: `程序异常:${e.reason}` }) } }) ``` 运行后查看控制台日志,定位具体错误文件行号(如:`pages/index/index.js:45`) #### 2. 修复异步操作(3种场景) ```javascript // 场景1: Promise忘记catch // ❌ 错误写法 fetchData().then(res => console.log(res)) // ✅ 修复方案 fetchData() .then(res => console.log(res)) .catch(err => console.error("请求失败:", err)) // 必须添加catch // 场景2: async/await未捕获 // ❌ 错误写法 async function loadData() { const res = await my.request({ url: 'api/getData' }) } // ✅ 修复方案 async function loadData() { try { const res = await my.request({ url: 'api/getData' }) } catch (err) { console.error("异步请求失败:", err) // 必须try/catch } } // 场景3: 小程序API调用 // ❌ 错误写法 my.getLocation({ success: () => {} }) // ✅ 修复方案 my.getLocation({ success: () => {}, fail: (err) => console.error("定位失败:", err) // 必须处理fail回调 }) ``` #### 3. 特殊场景处理 ```javascript // 场景:setTimeout/interval中的异步 setTimeout(async () => { try { // 需在异步内部捕获 await asyncOperation() } catch (e) { console.error("定时任务错误:", e) } }, 1000) // 场景:第三方库错误 import lib from 'third-party-lib' lib.init().catch(e => { // 显式捕获库异常 my.showToast({ title: '组件加载失败' }) }) ``` #### 4. 生产环境增强 在 `app.js` 中添加错误上报: ```javascript // 错误监控(接入阿里云ARMS等) onUnhandledRejection(e) { my.reportAnalytics('unhandled_rejection', { errMsg: e.reason.message, stack: e.reason.stack }) } ``` --- ### 预防措施 1. **ESLint 强制检测**: ```json // .eslintrc.json { "rules": { "no-unused-vars": "off", "@typescript-eslint/no-floating-promises": "error" // 强制Promise处理 } } ``` 2. **编码规范**: - 所有异步操作必须包含 `catch`/`fail` 处理 - 禁用 `Promise` 构造函数,改用 `async/await` - 小程序 API 调用必须完整填写 `success/fail/complete` 3. **测试验证**: ```bash # 强制触发拒绝测试 Promise.reject(new Error("测试拒绝")) .catch(e => console.log("测试通过")) ``` --- ### 相关问题 1. 如何捕获支付宝小程序全局 JavaScript 异常? 2. `my.request` 网络错误有哪些常见状态码? 3. 小程序中如何处理多个并发的异步操作? 4. 支付宝小程序错误监控系统如何接入? 5. 微信小程序支付宝小程序的 Promise 错误处理机制有何差异? > 通过上述方案可彻底解决 `onUnhandledRejection:ok` 错误,核心要点是保证**所有异步操作都有错误处理边界**。若问题持续,建议检查第三方插件或原生组件调用[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值