WKWebView通过loadrequest方法加载Post请求会丢失请求体(body)中的内容,进而导致服务器拿不到body中的内容的问题的发生。这个问题的产生主要是因为WKWebView的网络请求的进程与APP不是同一个进程,所以网络请求的过程是这样的:由APP所在的进程发起request,然后通过IPC通信(进程间通信)将请求的相关信息(请求头、请求行、请求体等)传递给webkit网络线进程接收包装,进行数据的HTTP请求,最终再进行IPC的通信回传给APP所在的进程的。这里如果发起的request请求是post请求的话,由于要进行IPC数据传递,传递的请求体body中根据系统调度,将其舍弃,最终在WKWebView网络进程接受的时候请求体body中的内容变成了空,导致此种情况下的服务器获取不到请求体,导致问题的产生。(摘自链接:关于WKWebView的post请求丢失body问题的解决方案 - 简书)
上面的问题通过测试发现在iOS11之后已修复,但是App还要支持iOS11之前的系统,所以还是需要解决这个问题。
解决思路
创建一个form表单,将需要post的数据填到表单,模拟form表单提交实现数据传输。
实现基础
新建一个头文件 WKWebViewFormDefine.h,里面定义了一个宏:
#define POST_JS @"function my_post(path, params) {\
var method = \"POST\";\
var form = document.createElement(\"form\");\
form.setAttribute(\"method\", method);\
form.setAttribute(\"action\", path);\
form.setAttribute(\"accept-charset\", \"UTF-8\");\
for(var key in params){\
if (params.hasOwnProperty(key)) {\
var hiddenFild = document.createElement(\"input\");\
hiddenFild.setAttribute(\"type\", \"hidden\");\
hiddenFild.setAttribute(\"name\", key);\
hiddenFild.setAttribute(\"value\", params[key]);\
}\
form.appendChild(hiddenFild);\
}\
document.body.appendChild(form);\
form.submit();\
}"
上面定义了一个my_post方法,需要传入两个参数:path和params,path是请求的URL的字符串,path是放到body中的参数,函数实现创建form表单并填入params的参数,最后commit提交,实现post请求。这个宏网上基本都能找到,但是实际使用中,当params中的汉字会出现乱码,上面已经补充,给from设置 accept-charset 问题解决。
实际使用
1、请求的url
urlStr = @''";
2、需要传入的参数字典
NSDictionary *params = @{@"key":@"value"};
3、将参数字典转成Json字符串
NSString*jsonString = [selfjsonStringFromDictionary:params];
4、包装成需要执行的 js 字符串,注意 my_post 是宏定义中的方法名,POST_JS是宏定义名称,需要一一对应!
NSString*jscript = [NSStringstringWithFormat:@"%@my_post(\"%@\", %@);",POST_JS, urlStr, jsonString];
5、执行js
[wkWebView evaluateJavaScript:jscript completionHandler:nil];
到这里基本实现完成了。
补充
上面实现中用到的函数
- (NSString*)jsonStringFromDictionary:(NSDictionary*)dcitionary
{
NSError*error =nil;
NSData*jsonData =nil;
if(!self) {
returnnil;
}
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dcitionaryenumerateKeysAndObjectsUsingBlock:^(id _Nonnullkey,id _Nonnullobj,BOOL*_Nonnullstop) {
NSString*keyString =nil;
NSString*valueString =nil;
if ([key isKindOfClass:[NSString class]]) {
keyString = key;
}else{
keyString = [NSStringstringWithFormat:@"%@",key];
}
if ([obj isKindOfClass:[NSString class]]) {
valueString = obj;
}else{
valueString = [NSStringstringWithFormat:@"%@",obj];
}
[dictsetObject:valueStringforKey:keyString];
}];
jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
if([jsonDatalength] ==0|| error !=nil) {
returnnil;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
returnjsonString;
}