Невозможно установить заголовки в моем запросе POK WKWebView
Я хочу сделать запрос POST для моего WKWebView
, но заголовки не будут установлены, когда я буду отслеживать запросы с Чарльзом, чтобы запрос не удался. Что здесь не так?
NSString *post = [NSString stringWithFormat: @"email=%@&password=%@", email, password];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *contentLength = [NSString stringWithFormat:@"%d", postData.length];
NSURL *url = [NSURL URLWithString:@"http://materik.me/endpoint"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:postData];
[request setValue:contentLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[webview loadRequest:request];
И это то, что Чарльз говорит, что запрос похож:
POST /endpoint HTTP/1.1
Host: materik.me
Content-Type: application/x-www-form-urlencoded
Origin: null
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (iPhone; CPU OS 8_0 like Mac OS X)
Content-Length: 0
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Итак, как вы можете видеть, Content-Length
есть 0
, Accept
не application/json
и не было отправлено тело запроса.
Спасибо за любую помощь.
Ответы
Ответ 1
У меня была такая же проблема с WKWebView, что я решил использовать вместо UIWebView, чтобы избежать сбоев сборщиков в iOS 8. Есть два способа, о которых я могу думать:
- Используйте NSURLConnection, чтобы выполнить запрос, а затем заполните WKWebView с данными ответа. Здесь вы можете найти пример:
fooobar.com/questions/199229/... (вам нужно только
connection:didReceiveData:
и connectionDidFinishLoading:
от делегата, если вы не используете самоподписанный сертификат SSL)
- Используйте JavaScript, чтобы выполнить запрос POST. Вот пример:
Создать файл, например. "POSTRequestJS.html":
<html>
<head>
<script>
//POST request example:
//post('URL', {key: 'value'});
function post(path, params) {
var method = "post";
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
for(var key in params) {
if(params.hasOwnProperty(key)) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
</script>
</head>
<body>
</body>
</html>
И в вашем коде после того, где вы хотите загрузить свой запрос:
NSString *path = [[NSBundle mainBundle] pathForResource:@"POSTRequestJS" ofType:@"html"];
NSString *html = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
WKWebView.navigationDelegate = self;
[WKWebView loadHTMLString:html baseURL:[[NSBundle mainBundle] bundleURL]];
Добавить метод:
- (void)makePostRequest
{
NSString *postData = [NSString stringWithFormat: @"email=%@&password=%@", email, password];
NSString *urlString = @"http://materik.me/endpoint";
NSString *jscript = [NSString stringWithFormat:@"post('%@', {%@});", urlString, postData];
DLog(@"Javascript: %@", jscript);
[WKWebView evaluateJavaScript:jscript completionHandler:nil];
didMakePostRequest = YES;
}
И последнее добавление WKNavigationDelegate:
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
if (!didMakePostRequest) {
[self makePostRequest];
}
}
Ответ 2
Как заявлял ОП, я также подтвердил в Чарльзе, что тело - 0 байт после webView.load(request)
.
Там обходной путь для этой ошибки WKWebView
, мы будем инициировать POST
запрос, используя URLSession, преобразовать данные, возвращаемые сервером, в String
и вместо загрузки url мы будем использовать loadHTMLString, который будет:
Задайте содержимое веб-страницы и базовый URL.
и контент - это наша преобразованная строка:
var request = URLRequest(url: URL(string: "http://www.yourWebsite")!)
request.httpMethod = "POST"
let params = "do=something&andAgain=something"
request.httpBody = params.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { (data : Data?, response : URLResponse?, error : Error?) in
if data != nil
{
if let returnString = String(data: data!, encoding: .utf8)
{
self.webView.loadHTMLString(returnString, baseURL: URL(string: "http://www.yourWebsite.com")!)
}
}
}
task.resume()
Ответ 3
Кажется, это ошибка.
https://bugs.webkit.org/show_bug.cgi?id=140188
Надеюсь, он будет рассмотрен в ближайшее время. В то же время возвращение к UIWebView или реализация обходного пути, предложенного Спасом Билярским в его ответе, кажется лучшим вариантом.
Ответ 4
Я использую этот метод делегата, и он работает!!!
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
NSLog(@"%@",navigationAction.request.allHTTPHeaderFields);
NSString *accessToken = @"Bearer 527d3401f16a8a7955aeae62299dbfbd";
NSMutableURLRequest *request = [navigationAction.request mutableCopy];
if(![[request.allHTTPHeaderFields allKeys] containsObject:@"Authorization"]){
[request setValue:accessToken forHTTPHeaderField:@"Authorization"];
decisionHandler(WKNavigationActionPolicyCancel);
[Helper hideProgressHUD];
[webView loadRequest:request];
} else {
decisionHandler(WKNavigationActionPolicyAllow);
}
}
Ответ 5
Я могу подтвердить эту проблему.
Простым обходным решением для меня был запрос AJAX, с jQuery:
$.ajax({
type : 'POST',
url : $('#checkout-form').attr('action'),
data : $('#checkout-form').serialize()
}).done(function(response, status) {
// response if return value 200
}).fail(function(status, error) {
console.log(error);
});
где моя форма выглядит как
<form id="checkout-form" method="POST" action="/shop/checkout">
...
</form>
Надеюсь, это поможет кому-то...
Ответ 6
WKWebView.load
метод не работает с почтовым запросом с телом сообщения. Вы должны использовать JavaScript для выполнения трюка, проверьте WKWebView.evaluateJavascript
.
Это может быть ошибка, но Apple до сих пор не обращалась к ней.
Ответ 7
обходной путь: трюк с помощью html5 и javascript.
Добавьте файл html5 с содержимым ниже в проект xcode. Опубликовать данные с помощью формы javascript и h5:
<html>
<head>
<script>
//how to call: post('URL', {"key": "value"});
function post(path, params) {
var method = "post";
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
for(var key in params) {
if(params.hasOwnProperty(key)) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
</script>
</head>
<body>
</body>
</html>
Загрузите файл h5 в WKWebView:
WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init];
config.preferences = [[WKPreferences alloc]init];
config.preferences.javaScriptEnabled = YES;
WKWebView* webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:config];
webView.navigationDelegate = self;
[self.view addSubview:webView];
NSString *path = [[NSBundle mainBundle] pathForResource:@"JSPOST" ofType:@"html"];
NSString *html = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[webView loadHTMLString:html baseURL:[[NSBundle mainBundle] bundleURL]];
Подготовьте параметры для публикации. то есть. строка и массив словаря
Примечание: при переходе массива в строку json с помощью NSJSONSerialization, '\ r' может быть добавлен автоматически. Вы должны удалить все "\ r" в строке json, или javascript не может быть правильно проанализирован.
// parameters to post
NSString* name = @"Swift";
NSArray* array = @[@{@"id":@"1", @"age":@"12"}, @{@"id":@"2", @"age":@"22"}];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:array options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
jsonString = [jsonString stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\'"];
// trim spaces and newline characters
jsonString = [jsonString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
jsonString = [jsonString stringByReplacingOccurrencesOfString:@"\r" withString:@""];
jsonString = [jsonString stringByReplacingOccurrencesOfString:@"\n" withString:@""];
NSString *postData = [NSString stringWithFormat: @"'name':'%@', 'contacts':'%@'", name, jsonString];
// page url to request
NSString *urlStr = @"http:api.example.com/v1/detail";
// javascript to evalute
NSString *jscript = [NSString stringWithFormat:@"post('%@',{%@});", urlStr, postData];
//NSLog(@"Javzascript: %@", jscript);
Поместите это в делегат WKWebView: didFinishNavigation
// call the javascript in step 3
(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
GCD_MAIN((^{
[_web evaluateJavaScript:jscript completionHandler:^(id object, NSError * _Nullable error) {
if (error) {
NSLog(@"----------->>>>>>>>>>>>> evaluateJavaScript error : %@", [error localizedDescription]);
}
}];
}));
}
Ответ 8
Swift3
Измените baseurl
и token
на ваши нужды.
extension MyWebView: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
let request: URLRequest = navigationAction.request
let urlString: String = request.url?.absoluteString ?? ""
let baseurl: String = "http://materik.me/"
let needsAuthorization: Bool = urlString.hasPrefix(baseurl)
if !needsAuthorization {
print("url doesn't need authorization. \(urlString)")
decisionHandler(.allow)
return
}
let headerFields: [String : String] = request.allHTTPHeaderFields ?? [:]
//print("url: \(urlString) fields: \(headerFields)")
if headerFields["Authorization"] != nil {
print("already has authorization header. \(urlString)")
decisionHandler(.allow)
return
}
print("add authorization header. \(urlString)")
let token: String = "sw_gu6GpGXRG50PR9oxewI"
var mutableRequest = request
mutableRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
decisionHandler(.cancel)
webView.load(mutableRequest)
}
}