How to add HTTP headers in request globally for iOS in swift

谁都会走 提交于 2019-11-26 12:44:50

问题


func webView(webView: WKWebView!, decidePolicyForNavigationAction navigationAction: WKNavigationAction!, decisionHandler: ((WKNavigationActionPolicy) -> Void)!) {
     var request = NSMutableURLRequest(URL: navigationAction.request.URL)
     request.setValue(\"value\", forHTTPHeaderField: \"key\")
     decisionHandler(.Allow)
}

In the above code I want to add a header to the request. I have tried to do navigationAction.request.setValue(\"IOS\", forKey: \"DEVICE_APP\") but it doesn\'t work.

please help me in any way.


回答1:


AFAIK sadly you cannot do this with WKWebView.

It most certainly does not work in webView:decidePolicyForNavigationAction:decisionHandler: because the navigationAction.request is read-only and a non-mutable NSURLRequest instance that you cannot change.

If I understand correctly, WKWebView runs sandboxed in a separate content and network process and, at least on iOS, there is no way to intercept or change it's network requests.

You can do this if you step back to UIWebView.




回答2:


There are many different ways to do that, I found that the easiest solution was to subclass WKWebView and override the loadRequest method. Something like this:

class CustomWebView: WKWebView {
    override func loadRequest(request: NSURLRequest) -> WKNavigation? {
        guard let mutableRequest = request.mutableCopy() as? NSMutableURLRequest else {
            return super.loadRequest(request)
        }
        mutableRequest.setValue("custom value", forHTTPHeaderField: "custom field")
        return super.loadRequest(mutableRequest)
    }
}

Then simply use the CustomWebView class as if it was a WKWebView.

EDIT NOTE: This will only work on the first request as pointed out by @Stefan Arentz.

NOTE: Some fields cannot be overridden and will not be changed. I haven't done a thorough testing but I know that the User-Agent field cannot be overridden unless you do a specific hack (check here for an answer to that)




回答3:


With some limitations, but you can do it. Intercept the response in the delegate function webView:decidePolicyFornavigationResponse:decisionHandler:, if the url changes cancel it by passing decisionHandler(.cancel) and reload the webview with newURLRequest which sets the custom headers and the intercepted url. In this way each time a url changes (e.g. users tap on links) you cancel that request and create a new one with custom headers.

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate  {
    var webView: WKWebView?
    var loadUrl = URL(string: "https://www.google.com/")!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView = WKWebView(frame: CGRect.zero)
        webView!.navigationDelegate = self
        view.addSubview(webView!)
        webView!.translatesAutoresizingMaskIntoConstraints = false
        webView!.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
        webView!.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
        webView!.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
        webView!.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true

        // Load first request with initial url
        loadWebPage(url: loadUrl)
    }

    func loadWebPage(url: URL)  {
        var customRequest = URLRequest(url: url)
        customRequest.setValue("some value", forHTTPHeaderField: "custom header key")
        webView!.load(customRequest)
    }

    // MARK: - WKNavigationDelegate

    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        guard let url = (navigationResponse.response as! HTTPURLResponse).url else {
            decisionHandler(.cancel)
            return
        }

        // If url changes, cancel current request which has no custom headers appended and load a new request with that url with custom headers
        if url != loadUrl {
            loadUrl = url
            decisionHandler(.cancel)
            loadWebPage(url: url)
        } else {
            decisionHandler(.allow)
        }
    }
}



回答4:


I have modified Au Ris answer to use NavigationAction instead of NavigationResponse, as jonny suggested. Also, this fixes situations where the same url is called subsequently and you don't have to keep track of the current url anymore. This only works for GET requests but can surely be adapted for other request types if neccessary.

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate  {
    var webView: WKWebView?

    override func viewDidLoad() {
        super.viewDidLoad()
        webView = WKWebView(frame: CGRect.zero)
        webView!.navigationDelegate = self
        view.addSubview(webView!)
        // [...] set constraints and stuff

        // Load first request with initial url
        loadWebPage(url: "https://my.url")
    }

    func loadWebPage(url: URL)  {
        var customRequest = URLRequest(url: url)
        customRequest.setValue("true", forHTTPHeaderField: "x-custom-header")
        webView!.load(customRequest)
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping
    (WKNavigationActionPolicy) -> Void) {
        if navigationAction.request.httpMethod != "GET" || navigationAction.request.value(forHTTPHeaderField: "x-custom-header") != nil {
            // not a GET or already a custom request - continue
            decisionHandler(.allow)
            return
        }
        decisionHandler(.cancel)
        loadWebPage(url: navigationAction.request.url!)
    }

}




回答5:


private var urlrequestCurrent: URLRequest?

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    //print("WEB decidePolicyFor navigationAction: \(navigationAction)")
    if let currentrequest = self.urlrequestCurrent {
        //print("currentrequest: \(currentrequest), navigationAction.request: \(navigationAction.request)")
        if currentrequest == navigationAction.request {
            self.urlrequestCurrent = nil
            decisionHandler(.allow)
            return
        }
    }

    decisionHandler(.cancel)

    var customRequest = navigationAction.request
    customRequest.setValue("myvaluefffs", forHTTPHeaderField: "mykey")
    self.urlrequestCurrent = customRequest
    webView.load(customRequest)
}



回答6:


Here's how you do it: The strategy is to have your WKNavigationDelegate cancel the request, modify a mutable copy of it and re-initiate it. An if-else is used to allow the request to proceed if it already has the desired header; otherwise you will end up in an endless load / decidePolicy loop.

Not sure what's up, but weird things happen if you set the header on every request, so for best results only set the header on requests to the domain(s) you care about.

The example here sets a header field for requests to header.domain.com, and allows all other requests without the header:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSURL * actionURL = navigationAction.request.URL;
    if ([actionURL.host isEqualToString:@"header.domain.com"]) {
        NSString * headerField = @"x-header-field";
        NSString * headerValue = @"value";
        if ([[navigationAction.request valueForHTTPHeaderField:headerField] isEqualToString:headerValue]) {
            decisionHandler(WKNavigationActionPolicyAllow);
        } else {
            NSMutableURLRequest * newRequest = [navigationAction.request mutableCopy];
            [newRequest setValue:headerValue forHTTPHeaderField:headerField];
            decisionHandler(WKNavigationActionPolicyCancel);
            [webView loadRequest:newRequest];
        }
    } else {
        decisionHandler(WKNavigationActionPolicyAllow);
    }
}


来源:https://stackoverflow.com/questions/28984212/how-to-add-http-headers-in-request-globally-for-ios-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!