面试题答案
一键面试应对高并发推送压力的设计优化方案
- 批量处理推送:
- 思路:将多个推送请求合并为一个批量请求发送给 APNs。这样可以减少与 APNs 的连接次数,提高效率。
- 关键代码片段:
NSMutableArray<UNNotificationRequest *> *requests = [NSMutableArray array]; // 假设已有多个通知内容,创建多个 UNNotificationRequest UNMutableNotificationContent *content1 = [UNMutableNotificationContent new]; content1.title = @"通知标题1"; content1.body = @"通知内容1"; UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5 repeats:NO]; UNNotificationRequest *request1 = [UNNotificationRequest requestWithIdentifier:@"request1" content:content1 trigger:trigger1]; [requests addObject:request1]; // 类似地创建更多 request 并添加到 requests 数组 UNNotificationResponse *response = [UNNotificationResponse responseWithActionIdentifier:@"defaultAction" notification:requests[0] ]; UNNotificationCenter *center = [UNNotificationCenter currentNotificationCenter]; [center addNotificationRequests:requests withCompletionHandler:^(NSError * _Nullable error) { if (error) { NSLog(@"批量添加通知请求出错: %@", error); } }];
- 缓存机制:
- 思路:在本地缓存一些推送相关的数据,如已推送的内容、推送时间等,避免重复推送相同内容。同时,可以缓存 APNs 的连接信息,减少建立新连接的开销。
- 关键代码片段:
// 使用 NSUserDefaults 简单缓存已推送通知的标识符 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSMutableArray<NSString *> *sentNotificationIDs = [defaults objectForKey:@"sentNotificationIDs"]; if (!sentNotificationIDs) { sentNotificationIDs = [NSMutableArray array]; } NSString *newNotificationID = @"newRequestID"; if (![sentNotificationIDs containsObject:newNotificationID]) { [sentNotificationIDs addObject:newNotificationID]; [defaults setObject:sentNotificationIDs forKey:@"sentNotificationIDs"]; [defaults synchronize]; // 执行推送操作 }
- 优化网络连接:
- 思路:使用长连接技术,保持与 APNs 的持续连接,避免频繁建立和断开连接。同时,合理设置网络超时时间,确保请求在合理时间内完成。
- 关键代码片段:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; configuration.timeoutIntervalForRequest = 10; // 设置请求超时时间为 10 秒 NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
确保推送内容安全性和完整性的方案
- 使用 HTTPS 协议:
- 思路:APNs 本身基于 HTTPS 协议,确保数据在传输过程中的加密。在 iOS 应用中,确保网络请求使用 HTTPS,防止中间人攻击。
- 关键代码片段:在应用的
Info.plist
文件中配置支持 HTTPS:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <false/> </dict>
- 数据加密:
- 思路:在发送推送内容之前,对敏感信息进行加密。可以使用对称加密(如 AES)或非对称加密(如 RSA)。
- 关键代码片段(使用 CommonCrypto 进行 AES 加密示例):
#import <CommonCrypto/CommonCryptor.h> NSData *encryptData(NSData *plainText, NSString *key) { char keyPtr[kCCKeySizeAES256 + 1]; bzero(keyPtr, sizeof(keyPtr)); [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [plainText length]; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesEncrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL, [plainText bytes], dataLength, buffer, bufferSize, &numBytesEncrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return nil; }
- 签名验证:
- 思路:在服务端对推送内容进行签名,客户端接收到推送后,验证签名的有效性,确保内容未被篡改。
- 关键代码片段(使用 CommonCrypto 进行 HMAC 签名验证示例):
#import <CommonCrypto/CommonHMAC.h> NSData *calculateHMAC(NSData *data, NSString *key) { const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding]; const char *cData = (const char *)[data bytes]; unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, [data length], cHMAC); return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]; } // 验证签名 NSData *receivedData = // 接收到的推送数据 NSData *receivedHMAC = // 接收到的签名 NSData *calculatedHMAC = calculateHMAC(receivedData, @"sharedSecretKey"); if ([calculatedHMAC isEqualToData:receivedHMAC]) { // 签名验证通过 } else { // 签名验证失败 }