AFNetworking源码解析<三>

2019年电赛D题《简易电路特性测试仪》全过程 2019年全国大学生电子设计大赛D题《简易电路特性测试仪》硬件部分及故障分析 阅读详情

续AFNetworking源码解析<一>、 <二>

本篇说说安全相关的AFSecurityPolicy模块,AFSecurityPolicy用于验证HTTPS请求的证书,先来看看HTTPS的原理和证书相关的几个问题。

HTTPS

HTTPS连接建立过程大致是,客户端和服务端建立一个连接,服务端返回一个证书,客户端里存有各个受信任的证书机构根证书,用这些根证书对服务端 返回的证书进行验证,经验证如果证书是可信任的,就生成一个pre-master  secret,用这个证书的公钥加密后发送给服务端,服务端用私钥解密后得到pre-master secret,再根据某种算法生成master  secret,客户端也同样根据这种算法从pre-master secret生成master secret,随后双方的通信都用这个master  secret对传输数据进行加密解密。

以上是简单过程,中间还有很多细节,详细过程和原理已经有很多文章阐述得很好,就不再复述,推荐一些相关文章:
关于非对称加密算法的原理:RSA算法原理<一>、<二>
关于整个流程:HTTPS那些事<一>、<二>、<三>
关于数字证书:浅析数字证书

这里说下一开始我比较费解的两个问题:

1.证书是怎样验证的?怎样保证中间人不能伪造证书?

首先要知道非对称加密算法的特点,非对称加密有一对公钥私钥,用公钥加密的数据只能通过对应的私钥解密,用私钥加密的数据只能通过对应的公钥解密。

我们来看最简单的情况:一个证书颁发机构(CA),颁发了一个证书A,服务器用这个证书建立https连接。客户端在信任列表里有这个CA机构的根证书。

首先CA机构颁发的证书A里包含有证书内容F,以及证书加密内容F1,加密内容F1就是用这个证书机构的私钥对内容F加密的结果。(这中间还有一次hash算法,略过。)

建立https连接时,服务端返回证书A给客户端,客户端的系统里的CA机构根证书有这个CA机构的公钥,用这个公钥对证书A的加密内容F1解密得 到F2,跟证书A里内容F对比,若相等就通过验证。整个流程大致是:F->CA私钥加密->F1->客户端CA公钥解密->F。 因为中间人不会有CA机构的私钥,客户端无法通过CA公钥解密,所以伪造的证书肯定无法通过验证。

2.什么是SSL Pinning?

可以理解为证书绑定,是指客户端直接保存服务端的证书,建立https连接时直接对比服务端返回的和客户端保存的两个证书是否一样,一样就表明证书 是真的,不再去系统的信任证书机构里寻找验证。这适用于非浏览器应用,因为浏览器跟很多未知服务端打交道,无法把每个服务端的证书都保存到本地,但CS架 构的像手机APP事先已经知道要进行通信的服务端,可以直接在客户端保存这个服务端的证书用于校验。

为什么直接对比就能保证证书没问题?如果中间人从客户端取出证书,再伪装成服务端跟其他客户端通信,它发送给客户端的这个证书不就能通过验证吗?确 实可以通过验证,但后续的流程走不下去,因为下一步客户端会用证书里的公钥加密,中间人没有这个证书的私钥就解不出内容,也就截获不到数据,这个证书的私 钥只有真正的服务端有,中间人伪造证书主要伪造的是公钥。

为什么要用SSL  Pinning?正常的验证方式不够吗?如果服务端的证书是从受信任的的CA机构颁发的,验证是没问题的,但CA机构颁发证书比较昂贵,小企业或个人用户 可能会选择自己颁发证书,这样就无法通过系统受信任的CA机构列表验证这个证书的真伪了,所以需要SSL Pinning这样的方式去验证。

AFSecurityPolicy

NSURLConnection已经封装了https连接的建立、数据的加密解密功能,我们直接使用NSURLConnection是可以访问 https网站的,但NSURLConnection并没有验证证书是否合法,无法避免中间人攻击。要做到真正安全通讯,需要我们手动去验证服务端返回的 证书,AFSecurityPolicy封装了证书验证的过程,让用户可以轻易使用,除了去系统信任CA机构列表验证,还支持SSL  Pinning方式的验证。使用方法:

1
2
3
4
5
6
7
//把服务端证书(需要转换成cer格式)放到APP项目资源里,AFSecurityPolicy会自动寻找根目录下所有cer文件
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
securityPolicy.allowInvalidCertificates = YES;
[AFHTTPRequestOperationManager manager].securityPolicy = securityPolicy;
[manager GET:@ "https://example.com/"  parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];

AFSecurityPolicy分三种验证模式:

AFSSLPinningModeNone

这个模式表示不做SSL pinning,只跟浏览器一样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会通过,若是自己服务器生成的证书,这里是不会通过的。

AFSSLPinningModeCertificate

这个模式表示用证书绑定方式验证证书,需要客户端保存有服务端的证书拷贝,这里验证分两步,第一步验证证书的域名/有效期等信息,第二步是对比服务端返回的证书跟客户端返回的是否一致。

这里还没弄明白第一步的验证是怎么进行的,代码上跟去系统信任机构列表里验证一样调用了SecTrustEvaluate,只是这里的列表换成了客户端保存的那些证书列表。若要验证这个,是否应该把服务端证书的颁发机构根证书也放到客户端里?

AFSSLPinningModePublicKey

这个模式同样是用证书绑定方式验证,客户端要有服务端的证书拷贝,只是验证时只验证证书里的公钥,不验证证书的有效期等信息。只要公钥是正确的,就能保证通信不会被窃听,因为中间人没有私钥,无法解开通过公钥加密的数据。

整个AFSecurityPolicy就是实现这这几种验证方式,剩下的就是实现细节了,详见源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
// AFSecurity.m
//
// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
  
#import "AFSecurityPolicy.h"
  
// Equivalent of macro in , without causing compiler warning:
// "'DebugAssert' is deprecated: first deprecated in OS X 10.8"
//这两个宏方法用于方便地处理调用各种证书方法过程中出现的错误,出现错误后用goto语句直接跳转到结束语
//关于为什么要用 __builtin_expect (x, 0) 而不直接用 x != 0,是为了CPU执行时的性能优化,见这里:
#ifndef AF_Require
#define AF_Require(assertion, exceptionLabel)                \
do  {                                                     \
if  (__builtin_expect(!(assertion), 0)) {             \
goto exceptionLabel;                             \
}                                                    \
}  while  (0)
#endif
  
#ifndef AF_Require_noErr
#define AF_Require_noErr(errorCode, exceptionLabel)          \
do  {                                                     \
if  (__builtin_expect(0 != (errorCode), 0)) {         \
goto exceptionLabel;                             \
}                                                    \
}  while  (0)
#endif
  
#if !defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
static NSData * AFSecKeyGetData(SecKeyRef key) {
     CFDataRef data = NULL;
  
     AF_Require_noErr(SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data), _out);
  
     return  (__bridge_transfer NSData *)data;
  
_out:
     if  (data) {
         CFRelease(data);
     }
  
     return  nil;
}
#endif
  
static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
     return  [(__bridge id)key1 isEqual:(__bridge id)key2];
#else
     return  [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)];
#endif
}
  
//从证书里取public key
static id AFPublicKeyForCertificate(NSData *certificate) {
     id allowedPublicKey = nil;
     SecCertificateRef allowedCertificate;
     SecCertificateRef allowedCertificates[1];
     CFArrayRef tempCertificates = nil;
     SecPolicyRef policy = nil;
     SecTrustRef allowedTrust = nil;
     SecTrustResultType result;
  
     //取证书SecCertificateRef -> 生成证书数组 -> 生成SecTrustRef -> 从SecTrustRef取PublicKey
     allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
     AF_Require(allowedCertificate != NULL, _out);
  
     allowedCertificates[0] = allowedCertificate;
     tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
  
     policy = SecPolicyCreateBasicX509();
     AF_Require_noErr(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
     AF_Require_noErr(SecTrustEvaluate(allowedTrust, &result), _out);
  
     allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
  
_out:
     if  (allowedTrust) {
         CFRelease(allowedTrust);
     }
  
     if  (policy) {
         CFRelease(policy);
     }
  
     if  (tempCertificates) {
         CFRelease(tempCertificates);
     }
  
     if  (allowedCertificate) {
         CFRelease(allowedCertificate);
     }
  
     return  allowedPublicKey;
}
  
static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
     BOOL isValid = NO;
     SecTrustResultType result;
     AF_Require_noErr(SecTrustEvaluate(serverTrust, &result), _out);
  
     //kSecTrustResultUnspecified:证书通过验证,但用户没有设置这些证书是否被信任
     //kSecTrustResultProceed:证书通过验证,用户有操作设置了证书被信任,例如在弹出的是否信任的alert框中选择always trust
     isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
  
_out:
     return  isValid;
}
  
//取出服务端返回的所有证书
static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) {
     CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
     NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];
  
     for  (CFIndex i = 0; i < certificateCount; i++) {
         SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
         [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
     }
  
     return  [NSArray arrayWithArray:trustChain];
}
  
//取出服务端返回证书里所有的public key
static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
     SecPolicyRef policy = SecPolicyCreateBasicX509();
     CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
     NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];
     for  (CFIndex i = 0; i  生成证书数组 -> 生成SecTrustRef -> 从SecTrustRef取PublicKey
         SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
  
         SecCertificateRef someCertificates[] = {certificate};
         CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL);
  
         SecTrustRef trust;
         AF_Require_noErr(SecTrustCreateWithCertificates(certificates, policy, &trust), _out);
  
         SecTrustResultType result;
         AF_Require_noErr(SecTrustEvaluate(trust, &result), _out);
  
         [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)];
  
     _out:
         if  (trust) {
             CFRelease(trust);
         }
  
         if  (certificates) {
             CFRelease(certificates);
         }
  
         continue ;
     }
     CFRelease(policy);
  
     return  [NSArray arrayWithArray:trustChain];
}
  
#pragma mark -
  
@interface AFSecurityPolicy()
@property (readwrite, nonatomic, strong) NSArray *pinnedPublicKeys;
@end
  
@implementation AFSecurityPolicy
  
+ (NSArray *)defaultPinnedCertificates {
     //默认证书列表,遍历根目录下所有.cer文件
     static NSArray *_defaultPinnedCertificates = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         NSBundle *bundle = [NSBundle bundleForClass:[self class]];
         NSArray *paths = [bundle pathsForResourcesOfType:@ "cer"  inDirectory:@ "." ];
  
         NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]];
         for  (NSString *path  in  paths) {
             NSData *certificateData = [NSData dataWithContentsOfFile:path];
             [certificates addObject:certificateData];
         }
  
         _defaultPinnedCertificates = [[NSArray alloc] initWithArray:certificates];
     });
  
     return  _defaultPinnedCertificates;
}
  
+ (instancetype)defaultPolicy {
     AFSecurityPolicy *securityPolicy = [[self alloc] init];
     securityPolicy.SSLPinningMode = AFSSLPinningModeNone;
  
     return  securityPolicy;
}
  
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
     AFSecurityPolicy *securityPolicy = [[self alloc] init];
     securityPolicy.SSLPinningMode = pinningMode;
     securityPolicy.validatesDomainName = YES;
     [securityPolicy setPinnedCertificates:[self defaultPinnedCertificates]];
  
     return  securityPolicy;
}
  
- (id)init {
     self = [ super  init];
     if  (!self) {
         return  nil;
     }
  
     self.validatesCertificateChain = YES;
  
     return  self;
}
  
#pragma mark -
  
- (void)setPinnedCertificates:(NSArray *)pinnedCertificates {
     _pinnedCertificates = pinnedCertificates;
  
     if  (self.pinnedCertificates) {
         //预先取出public key,用于AFSSLPinningModePublicKey方式的验证
         NSMutableArray *mutablePinnedPublicKeys = [NSMutableArray arrayWithCapacity:[self.pinnedCertificates count]];
         for  (NSData *certificate  in  self.pinnedCertificates) {
             id publicKey = AFPublicKeyForCertificate(certificate);
             if  (!publicKey) {
                 continue ;
             }
             [mutablePinnedPublicKeys addObject:publicKey];
         }
         self.pinnedPublicKeys = [NSArray arrayWithArray:mutablePinnedPublicKeys];
     }  else  {
         self.pinnedPublicKeys = nil;
     }
}
  
#pragma mark -
  
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust {
     return  [self evaluateServerTrust:serverTrust forDomain:nil];
}
  
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                   forDomain:(NSString *)domain
{
     NSMutableArray *policies = [NSMutableArray array];
     if  (self.validatesDomainName) {
         [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL( true , (__bridge CFStringRef)domain)];
     }  else  {
         [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
     }
  
     SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
  
     //向系统内置的根证书验证服务端返回的证书是否合法
     //若使用自签名证书,这里的验证是会不合法的,需要设allowInvalidCertificates = YES
     if  (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
         return  NO;
     }
  
     //取出服务端返回的证书
     NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
     switch  (self.SSLPinningMode) {
         case  AFSSLPinningModeNone:
             //两种情况走到这里,
             //一是通过系统证书验证,返回认证成功
             //二是没通过验证,但allowInvalidCertificates = YES,也就是说完全不认证直接返回认证成功
             return  YES;
  
             //验证整个证书
         case  AFSSLPinningModeCertificate: {
             NSMutableArray *pinnedCertificates = [NSMutableArray array];
             for  (NSData *certificateData  in  self.pinnedCertificates) {
                 [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
             }
             //在本地证书里验证服务端返回的证书的有效性
             SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
             if  (!AFServerTrustIsValid(serverTrust)) {
                 return  NO;
             }
  
             if  (!self.validatesCertificateChain) {
                 return  YES;
             }
  
             //整个证书链都跟本地的证书匹配才给过
             NSUInteger trustedCertificateCount = 0;
             for  (NSData *trustChainCertificate  in  serverCertificates) {
                 if  ([self.pinnedCertificates containsObject:trustChainCertificate]) {
                     trustedCertificateCount++;
                 }
             }
  
             return  trustedCertificateCount == [serverCertificates count];
         }
  
             //只验证证书的public key
         case  AFSSLPinningModePublicKey: {
             NSUInteger trustedPublicKeyCount = 0;
             NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
  
             //如果不用验证整个证书链,取第一个也就是真正会使用的那个证书验证就行
             if  (!self.validatesCertificateChain && [publicKeys count] > 0) {
                 publicKeys = @[[publicKeys firstObject]];
             }
  
             //在本地证书里搜索相等的public key,记录找到个数
             for  (id trustChainPublicKey  in  publicKeys) {
                 for  (id pinnedPublicKey  in  self.pinnedPublicKeys) {
                     if  (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
                         trustedPublicKeyCount += 1;
                     }
                 }
             }
  
             //验证整个证书链的情况:每个public key都在本地找到算验证通过
             //验证单个证书的情况:找到一个算验证通过
             return  trustedPublicKeyCount > 0 && ((self.validatesCertificateChain && trustedPublicKeyCount == [serverCertificates count]) || (!self.validatesCertificateChain && trustedPublicKeyCount >= 1));
         }
     }
  
     return  NO;
}
  
#pragma mark - NSKeyValueObserving
  
+ (NSSet *)keyPathsForValuesAffectingPinnedPublicKeys {
     return  [NSSet setWithObject:@ "pinnedCertificates" ];
}
  
@end
【Claude Code】Unable to connect to API 报错原因与排查解决全流程 深入分析 Claude Code 中 Unable to connect to API 系列报错的根因,涵盖 ECONNREFUSED、ECONNRESET、ETIMEDOUT 等 6 种变体,提供从网络连通性检测、代理配置到 LLM 网关路由的完整排查路径,帮助开发者快速恢复 Claude Code 的正常使用。 阅读详情

相关推荐

Openbmc系列之自动化测试框架1

Openbmc作为当下BMC固件领域最流行的开源软件,具备从需求计划、开发、调试、测试、版本管理等完整的体系。在测试领域,Openbmc基于python的robotframework框架,实现Openbmc的自动化测试,为高效发布Openbmc版本提供有力支持。本文作为测试系列文档一,介绍Openbmc自动化测试虚拟Openbmc的环境搭建。

qq_20341747的博客 2109

AFSecurityPolicy 之 evaluateServerTrust

针对 TLS HandShake 中服务器下发的 `Certificate`,macOS/iOS 的 Security.framework 的 SecPolicy.h/SecTrust.h 中定义了证书校验信任评估的接口。 调用 `SecTrustEvaluate` 对证书校验通过后,客户端需要基于对服务器的信任来建立凭证。

曾梦想仗剑走天涯 2670

STM32移植LVGL(LittleVGL)

**STM32移植LVGL(LittleVGL)**

qq_53000374的博客 1万+

AFNetworking 3.0 源码解读(二)之 AFSecurityPolicy

在我们平时的开发中,对网络连接安全方面所做的努力,应该占据很重要的位置。 在解释AFSecurityPolicy之前,我们先把基础的http/https 知识简单的普及一下。获取这方面的信息可通过这本书:图解HTTP  HTTP: 1.HTTP协议用于客户端和服务器端之间的通信 2.通过请求和相应的交换达成通信 客户端请求:   服务器端响应: 3.HTTP是不保存状态的协...

weixin_33700350的博客 242

UE4打包为Framework库嵌入iOS原生工程

UE4打包为Framework库嵌入iOS原生工程

tangfuling1991的博客 1294

Cadence OrCAD Capture 保持元器件编号情况复制元件,复制后元器件编号与复制前不同的问题解决

如下图所示复制时,已经勾选了“Preserve reference on copy”但是复制后的编号却与复制前不一样。本文简单介绍其原因及解决方法。

fydar的博客 3163

AFNetworking之于https认证

是服务器传过来的,里面包含了服务器的证书信息,是用来我们本地客户端去验证该证书是否合法用的,后面会更详细的去讲这个参数)然后如果有证书,则用证书认证方式,否则还是用默认的验证方式。再讲简单点,其实就是一个容器,装了服务器端需要验证的证书的基本信息、公钥等等,不仅如此,它还可以装一些评估策略,还有客户端的锚点证书,这个客户端的证书,可以用来和服务端的证书去匹配验证的。唯一需要注意的是,这个获取的证书排序,是从证书链的叶节点,到根节点的。客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容。

gcs的博客 1166

【人工智能】OpenClaw网关API速率限制报错全解析 API rate limit reached. Please try again later.

对应HTTP标准状态码为429(请求过多)。该报错集中出现在OpenClaw GATEWAY DASHBOARD的聊天会话界面,核心特征为:用户最初以为是单一模型服务商的问题,先后更换OpenAI、Gemini、Ollama、Moonshot、Mercury-2等多个主流大模型API后,该报错仍稳定触发,尤其在执行复杂任务时高频出现。

奶爸的编程之路,也就一周冷个三天 6458

AFNetworking 3.0 https请求忽略证书验证

1、修改AFNetworking中修改源码,在AFSecurityPolicy.m注释掉这几句 - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain { // if (domain && self.allowInvalidCertificates

Litchi的专栏 5389

【MATLAB】STM32电机调速闭环控制工程

本文提出了一种基于MATLAB仿真与STM32实现的直流电机闭环PID调速控制方案。通过MATLAB建立电机数学模型并进行参数整定,仿真验证了增量式PID算法在启停、稳态和抗扰动方面的优越性能。基于STM32F103搭建了硬件系统,实现了编码器测速、定时中断控制、PWM输出等功能。实测表明,该系统转速超调<2%、稳态误差±2r/min,具备快速响应和强抗扰能力。相比开环控制,闭环调速显著提升了动态性能和稳态精度。方案提供了完整的仿真代码和嵌入式工程源码,可直接应用于智能小车、工业传动等场景,具有较高的

unber的博客 49

NX二次开发新建组件

NXOpen新建组件

qq_39541524的博客 329

AFNetworking2.0源码解析<三>

http://blog.cnbang.net/tech/2416/ 续AFNetworking源码解析 本篇说说安全相关的AFSecurityPolicy模块,AFSecurityPolicy用于验证HTTPS请求的证书,先来看看HTTPS的原理和证书相关的几个问题。 HTTPS HTTPS连接建立过程大致是,客户端和服务端建立一个连接,服务端返回一个证书,客户端里

jeffasd的专栏 381

一次携程酒店 phantom-token 逆向实战复盘(附python纯算)

摘要 本文介绍了通过分析携程酒店列表页面的数据接口,使用Python实现抓取的方法。主要内容包括: 目标站点为携程酒店列表页,通过开发者工具发现关键接口fetchHotelList 将浏览器请求转换为Python代码,包含请求头(headers)、Cookies和POST数据 提供完整的请求示例代码,包含日期参数、城市ID等必要信息 特别声明仅供学习交流使用,禁止商业用途 展示了如何获取酒店列表数据,包括排序筛选等参数设置 该方法可用于研究酒店数据采集,但需要注意遵守网站使用条款。

自成背后的博客 3020

AFNetworking (3.1.0) 源码解析 <三>

今天要介绍的是Reachability文件夹下的AFNetworkReachabilityManager类。通过字面意思我们就可以知道AFNetworkReachabilityManager是用来监测网络状态,网络状态管理的类,他可以通过设置状态改变回调来获得当前网络状态。 下面我们还是先看.h文件。 上边枚举表示的是网络状态,网络状态有以上几种,分别是未知,不可用,无线广域网连...

145

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

AFNetworking2.0源码解析<二>

续AFNetworking2.0源码解析 本篇我们继续来看看AFNetworking的下一个模块 — AFURLRequestSerialization。 AFURLRequestSerialization用于帮助构建NSURLRequest,主要做了两个事情: 1.构建普通请求:格式化请求参数,生成HTTP Header。 2.构建multipart请求。 分别看看它在这两点具

sunyazhou13的专栏 613

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: AFNetworking2.0源码解析<二>
下一篇: iPhone屏幕分辨率
focusjava
博客等级 码龄14年 127粉丝 528原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值