WKURLSchemeHandler是否支持XMLHTTPRequest携带的FormData请求体?
WKURLSchemeHandler本身支持将FormData作为请求体,你遇到的HTTPBody、HTTPBodyStream为nil的问题是WebKit针对自定义scheme的POST请求的默认优化逻辑导致的,不是功能不支持。
根因说明
- WKWebView的网络请求处理默认在独立的WebKit进程中执行,为了避免大体积请求体多次跨进程拷贝带来的内存开销,WebKit对自定义scheme的POST请求默认会丢弃请求体内容,不管请求体是普通表单、JSON还是FormData格式,都会出现HTTPBody、HTTPBodyStream为nil的情况。
可用解决方案
方案1:JS侧透传序列化后的FormData内容
- JS端发送携带FormData的XHR前,先将FormData序列化为可传输的字符串格式(二进制文件可先转base64编码),存入自定义请求头,比如
X-Custom-Form-Data,同时把对应的Content-Type值也存入X-Custom-Content-Type自定义头。 - WKURLSchemeHandler侧从
WKURLSchemeTask.request.allHTTPHeaderFields中取出上述自定义头的内容,自行解析组装即可得到完整的FormData数据。
该方案无系统版本适配风险,兼容性最好,适合FormData体积不大的场景。
方案2:Hook WKWebView请求逻辑强制保留请求体
- 可以通过Runtime交换NSURLRequest的
HTTPBody方法,主动读取HTTPBodyStream的内容补全请求体,核心实现代码如下:
#import <objc/runtime.h> @implementation NSURLRequest (FormDataFix) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class targetCls = NSClassFromString(@"WKNSURLRequest"); if (!targetCls) return; SEL originalSel = @selector(HTTPBody); SEL swizzledSel = @selector(custom_getHTTPBody); Method originalMethod = class_getInstanceMethod(targetCls, originalSel); Method swizzledMethod = class_getInstanceMethod(self, swizzledSel); if (originalMethod && swizzledMethod) { method_exchangeImplementations(originalMethod, swizzledMethod); } }); } - (NSData *)custom_getHTTPBody { NSData *originalBody = [self custom_getHTTPBody]; if (originalBody) return originalBody; // 从HTTPBodyStream读取内容 NSInputStream *stream = self.HTTPBodyStream; if (!stream) return nil; NSMutableData *bodyData = [NSMutableData data]; uint8_t buffer[1024 * 4]; NSInteger readLength; [stream open]; while ((readLength = [stream read:buffer maxLength:sizeof(buffer)]) > 0) { [bodyData appendBytes:buffer length:readLength]; } [stream close]; return bodyData; } @end
该方案依赖WebKit内部私有类结构,iOS系统大版本升级可能出现兼容性问题,需要做好验证适配。
方案3:使用HTTP/HTTPS作为拦截scheme
- 如果你的业务不需要完全自定义非标准scheme,可以直接用
WKURLSchemeHandler注册http/https scheme做请求拦截,这种场景下WebKit不会默认丢弃POST请求体,你可以直接从WKURLSchemeTask.request中拿到完整的FormData内容。
内容的提问来源于stack exchange,提问作者Silin Vasya
相关产品推荐
相关产品推荐

