SoFunction
Updated on 2025-03-02

Android webview intercepts H5's interface request and returns the processed data code example

Android webview intercepts H5's interface request and returns processed data

Android can passWebViewofshouldInterceptRequestMethod intercepts network requests in H5. This is oneWebViewClientThe callback method in   allows developers to process and modify WebView when it initiates a network request.

The specific usage method is as follows:

  • You need to create a custom oneWebViewClient, and rewrittenshouldInterceptRequestmethod.

  • In this method, you can intercept web requests initiated by the WebView and return a custom response, or let the request continue.

  • This method introduces two overloaded methods in API 21 (Android 5.0) and later:

    • shouldInterceptRequest(WebView view, String url) (API 11)
    • shouldInterceptRequest(WebView view, WebResourceRequest request) (API 21)

Here is a code example:

// Kotlin code example = object : WebViewClient() {
    // For API 21 and later    override fun shouldInterceptRequest(
        view: WebView, 
        request: WebResourceRequest
    ): WebResourceResponse? {
        val url = ()
        // Here you can judge the URL and intercept or modify the request as needed        if (("your_target_url")) {
            // Some processing can be done here, such as replacing the request or returning local data            val inputStream = ... // Custom input stream            return WebResourceResponse("text/html", "UTF-8", inputStream)
        }
        // Don't intercept, continue to request        return (view, request)
    }
    
    // For API 11 to API 20 devices    override fun shouldInterceptRequest(
        view: WebView, 
        url: String
    ): WebResourceResponse? {
        // The processing logic here is similar to the above code        if (("your_target_url")) {
            // Custom processing logic            val inputStream = ... 
            return WebResourceResponse("text/html", "UTF-8", inputStream)
        }
        return (view, url)
    }
}

existshouldInterceptRequestIn the method, you can return aWebResourceResponseObject to change or replace the original network request, and the request can also be continued through the default implementation.

Get the data requested by the network interface (such as the response of the API request) and return it to H5.

There are several ways to consider:

1. Intercept the request and initiate the request manually

You can passshouldInterceptRequestMethods intercept WebView's API requests and use them in Java or Kotlin.HttpURLConnectionorOkHttpStart a network request, and after processing the response, pass the response data to H5.

Sample code:

 = object : WebViewClient() {
    override fun shouldInterceptRequest(
        view: WebView, 
        request: WebResourceRequest
    ): WebResourceResponse? {
        val url = ()

        // Determine whether it is an interface request that needs to be intercepted        if (("your_api_endpoint")) {
            //Stamp the request via OkHttp or HttpURLConnection            val response = fetchApiData(url)

            // Pass the retrieved response content to H5             {
                ("javascript:handleApiResponse('${response}')", null)
            }

            // Return an empty response or custom content            return WebResourceResponse("application/json", "UTF-8", null)
        }

        return (view, request)
    }

    // Use OkHttp to initiate network requests (you can choose the appropriate network library according to your needs)    private fun fetchApiData(url: String): String {
        // Simple OkHttp request example        val client = OkHttpClient()
        val request = ().url(url).build()

        (request).execute().use { response ->
            return ?.string() ?: ""
        }
    }
}

In this example,shouldInterceptRequestIt will intercept the specified network request and then useOkHttpStart a request and pass the obtained response data throughevaluateJavascriptThe method is passed back to the H5 page in the WebView.

2. JavaScript communication through WebView and H5

Another way is through WebViewaddJavascriptInterfaceMethod, communicate Android code with H5. When Android initiates a request, data can be passed to H5 through the interface.

Define a JavaScript function in H5 to receive data:

function handleApiResponse(response) {
    ("API Response: ", response);
    // Here you can process the response, render to the page, etc.}

On the Android side:

(object {
    @JavascriptInterface
    fun sendDataToH5(data: String) {
        // Send data to H5        ("javascript:handleApiResponse('$data')", null)
    }
}, "AndroidInterface")

 = object : WebViewClient() {
    override fun shouldInterceptRequest(
        view: WebView, 
        request: WebResourceRequest
    ): WebResourceResponse? {
        val url = ()
        
        if (("your_api_endpoint")) {
            val response = fetchApiData(url)
            
            // Pass data to H5 through JavaScript interface             {
                ("javascript:AndroidInterface.sendDataToH5('${response}')", null)
            }
            
            return WebResourceResponse("application/json", "UTF-8", null)
        }
        return (view, request)
    }
}

Does this need to take into account the type of network interface request sent by H5? Post or get

Yes, in useshouldInterceptRequestWhen intercepting network requests sent by H5,The type of request (GET or POST) needs to be considered. This is because GET and POST requests are handled differently, especially POST requests, which carry body data, while GET requests usually only contain URL parameters.

shouldInterceptRequestIt can help you intercept requests, but when handling POST requests, special attention should be paid to extracting and using the request body.

How to distinguish between GET and POST requests?

In API 21 and later,shouldInterceptRequestThe method ofWebResourceRequestThe object contains more information, and can be used through itsgetMethod()Methods to distinguish request types.

override fun shouldInterceptRequest(
    view: WebView, 
    request: WebResourceRequest
): WebResourceResponse? {
    val url = ()
    val method =   // Get request method such as GET or POST
    // Process according to the request type    if (method == "POST") {
        // Get the body requested by POST (in Android WebView, it is not supported to directly obtain the POST body unless a specific tool is used)        // Custom logic processing POST requests    } else if (method == "GET") {
        // Process GET requests    }

    return (view, request)
}

Processing POST requests

Android'sshouldInterceptRequestIt does not directly provide the function of obtaining the POST request body. However, you can use other ways to handle it, such as passing the request body to Android in advance in JS.

Method 1: Use evaluateJavascript to pass POST request data

You can have the H5 page send the POST requested data to the WebView in advance through JavaScript before making a POST request. The Android side can then intercept and process this data.

  • Intercept and pass POST request data in H5:

    function interceptAndSendPostData(url, data) {
        // Call the Android interface to pass data to WebView    (url, (data));
        
        // Continue to initiate POST request    fetch(url, {
            method: "POST",
            body: (data),
            headers: {
                "Content-Type": "application/json"
            }
        }).then(response => ())
          .then(data => (data));
    }
    
  • Receive POST data in Android:

    (object {
        @JavascriptInterface
        fun sendPostData(url: String, data: String) {
            // Here you can process the passed POST request data        ("WebView", "POST request URL: $url, data: $data")
        }
    }, "AndroidInterface")
    

Method 2: Send POST requests through custom network layer

Another way is toshouldInterceptRequestAfter intercepting the POST request, the HTTP request is manually initiated to process the request body and response data. AlthoughshouldInterceptRequestThe request body is not provided directly, but you can pass the POST request body to Android in advance through JavaScript in the H5 page, or handle it through other network interception methods (such as using OkHttp's interceptor).

override fun shouldInterceptRequest(
    view: WebView, 
    request: WebResourceRequest
): WebResourceResponse? {
    val url = ()
    val method =   // Get request method such as GET or POST
    if (method == "POST") {
        // Customize the HTTP request to process POST request body and response        val response = performCustomHttpPost(url, request)
        return WebResourceResponse("application/json", "UTF-8", response)
    }

    return (view, request)
}

fun performCustomHttpPost(url: String, request: WebResourceRequest): InputStream {
    // Send custom POST requests using OkHttp or HttpURLConnection    val client = OkHttpClient()
    val requestBody = ... // Build the request body
    val request = ()
        .url(url)
        .post(requestBody)
        .build()

    val response = (request).execute()
    return ?.byteStream() ?: ByteArrayInputStream(ByteArray(0))
}

summary

  • GET Request: You can intercept and process directly through URL and request header information.
  • POST request: Special processing of request volume data is required. You can pass POST request data to the WebView in advance through JavaScript, or process POST requests and their responses by manually initiating HTTP requests.

Can InterceptRequest determine the type of network request? For example, script xhr, etc.

shouldInterceptRequestIt cannot directly determine the specific type of network request (such asscriptxhr, etc.), because it does not provide a field that explicitly indicates that the request is a resource of some type (such as JavaScript files, XHR requests, etc.). However, you can request itURLandRequest header informationTo infer the request type.

In Android versions of API 21 and above,WebResourceRequestThe object provides rich information, including the requested URL, request method (GET, POST, etc.), request header, etc., and the request type can be inferred based on this information.

How to determine the request type by URL and request header?

  • By URL suffix

    • If the requested URL is.jsAt the end, it can usually be considered as ascriptask.
    • If the URL contains/api/or similar identifiers, which may bexhrask.
    • CSS usually.cssAt the end, the picture file is.jpg.png.gifEnding, etc.
  • Pass request header: You can infer the request type by the request header, for exampleAcceptThe header usually indicates the type of data the client expects to receive.

    • Accept: application/jsonCommonly used inxhrask.
    • Accept: text/cssIndicates the request for a CSS file.
    • Accept: application/javascriptorAccept: text/javascriptUsed for JavaScript file requests.

Code example: How to infer a request type by URL and request header

override fun shouldInterceptRequest(
    view: WebView, 
    request: WebResourceRequest
): WebResourceResponse? {
    val url = ()
    val headers = 
    val acceptHeader = headers["Accept"]  // Get the Accept header
    // Determine whether it is a script request (script)    if ((".js") || acceptHeader?.contains("application/javascript") == true) {
        ("WebView", "Intercept script request: $url")
        // You can intercept or modify script requests here    }

    // Determine whether it is an XHR request (judged by URL or Accept header)    if (("/api/") || acceptHeader?.contains("application/json") == true) {
        ("WebView", "Intercepted XHR request: $url")
        // Here you can intercept or modify XHR requests    }

    // Determine whether it is a CSS request    if ((".css") || acceptHeader?.contains("text/css") == true) {
        ("WebView", "Intercepted CSS request: $url")
        // CSS requests can be intercepted or modified here    }

    // Requests for other resource types    ("WebView", "Other types of requests: $url")
    
    return (view, request)
}

How to judge common resource types

  • JavaScript file request (script)
    • Judging by URL:(".js")
    • passAcceptHead judgment:application/javascriptortext/javascript
  • XHR Request
    • Judging by URL rules: If the URL contains/api//ajax/or other common API paths.
    • passAcceptHead judgment:application/json
  • CSS file request
    • Judging by URL:(".css")
    • passAcceptHead judgment:text/css
  • Image file request
    • Judging by URL:(".jpg").png.gifwait
    • passAcceptHead judgment:image/*
  • HTML page request
    • passAcceptHead judgment:text/html

summary

AlthoughshouldInterceptRequestThere is no field directly provided for resource type, but you can use the URL format and request header (especiallyAcceptheader) to infer the request type and thus intercept specific resource requests.

What are script xhr font png preflight and how should we judge? Can we judge them by val acceptHeader = headers["Accept"]?

AcceptThe header indicates the type of response data the client wants to receive in an HTTP request. It can indeed help us determine the type of resource requested in some cases. But not all types of requests will be used explicitly.Accepthead. Therefore, we need to combineURLandRequest headerOther information (such asContent-TypeAccess-Control-Request-Methodetc.) to make judgments.

1. Script (JavaScript Request)

JavaScript requests are used to load.jsFile resource request.

Judgment basis:

  • URL suffix: Usually.jsFile suffix.
  • Acceptheadapplication/javascriptortext/javascript
if ((".js") || acceptHeader?.contains("application/javascript") == true || acceptHeader?.contains("text/javascript") == true) {
    ("WebView", "Intercepted JavaScript request: $url")
}

2. XHR request (XMLHttpRequest/Fetch request)

XHR requests are usually used for AJAX requests or useFetch APIasynchronous network requests.

Judgment basis:

  • URL Rules: API requests usually have specific paths, such as/api//ajax/wait.
  • Accepthead:application/json(If JSON data is returned).
  • Request header:XHR request will carryX-Requested-With: XMLHttpRequestHead (but not all cases have this head).
if (("/api/") || acceptHeader?.contains("application/json") == true || headers["X-Requested-With"] == "XMLHttpRequest") {
    ("WebView", "Intercepted XHR request: $url")
}

3. Font request (font file request)

Font files are usually.woff.woff2.ttf.otfEven the end of the suffix.

Judgment basis:

  • URL suffix.woff.woff2.ttf.otf
  • Accepthead:font/*orapplication/font-woff
if ((".woff") || (".woff2") || (".ttf") || (".otf") || acceptHeader?.contains("font/") == true) {
    ("WebView", "Intercepted font file request: $url")
}

4. PNG request (picture request)

Image requests usually include.png.jpg.gifetc.

Judgment basis:

  • URL suffix: Picture files are usually.png.jpg.jpeg.gifEnd.
  • Accepthead:image/*
if ((".png") || (".jpg") || (".jpeg") || (".gif") || acceptHeader?.contains("image/") == true) {
    ("WebView", "Intercepted image request: $url")
}

5. Preflight request

A Preflight request is part of a CORS request and is usually sent before a cross-domain POST, PUT, DELETE request to determine whether the server allows the request. Preflight request to useOPTIONSMethod initiated.

Judgment basis:

  • HTTP MethodsOPTIONS(Preflight request isOPTIONSRequest of method).
  • Request header:IncludeAccess-Control-Request-MethodandAccess-Control-Request-Headers
if ( == "OPTIONS" && ("Access-Control-Request-Method")) {
    ("WebView", "Intercept Preflight request: $url")
}

Combine the URL and Accept header for judgment

Summarize the basis for judging different request types:

Request Type URL suffix Accepthead Other request header information
Script (JavaScript) .js application/javascripttext/javascript
XHR (AJAX) /api//ajax/ application/json X-Requested-With: XMLHttpRequest
Font (font) .woff.woff2.ttf.otf font/*application/font-woff
Image (Picture) .png.jpg.jpeg.gif image/*
Preflight (CORS) OPTIONSmethod,Access-Control-Request-Method

summary

  • AcceptThe header can help determine the request type, but not all requests use it explicitly.
  • According to URL suffix, request method, other request headers (such asX-Requested-WithAccess-Control-Request-Method) Combining judgment can more accurately identify different types of requests.

How to deal with the response returned does not meet the expected format

AppearAxiosError: Network Error, Code: ERR_NETWORKErrors are usually because the response returned by the WebView does not meet the expected format when processing intercepted network requests, or some necessary header information is missing. Here are a few common reasons and solutions:

Possible causes of the problem:

  • Response stream format or processing error: You are returning()?.byteStream(), but you still need to ensure the wholeWebResourceResponseObjects are correctly configured, especially content type, encoding format and response header information. Any error can cause H5 (for example through Axios) to think that the network request has failed.

  • Missing or incomplete response header: WebResourceResponseSome key response headers need to be provided, such asContent-TypeandContent-Length, These headers are required in network request processing. Axios requested by H5 need to know the length and type of the response, otherwise the response will be considered invalid.

  • The returned stream is incomplete or closed in advance: If there is a problem with the returned stream, such as it is closed in advance or has other exceptions, it may cause Axios to report an error during processing.

How to correctly return a custom response

Make sure you useWebResourceResponseWhen building the response, all necessary header information and stream data are included.

Modify code example

override fun shouldInterceptRequest(
    view: WebView, 
    request: WebResourceRequest
): WebResourceResponse? {
    val url = ()
    
    if (("your_api_endpoint")) {
        // Initiate a network request to obtain data        val response = fetchApiData(url)
        
        // Process the returned response stream        val byteStream = ?.byteStream() ?: ByteArrayInputStream(ByteArray(0))
        val contentType = ("Content-Type", "application/json") // Set the default content type        val contentLength = ("Content-Length", "-1").toLong() // Set content length        
        // Build WebResourceResponse and return it to WebView        return WebResourceResponse(
            contentType, // Content Type            "utf-8",     // Encoding format            200,         // HTTP status code            "OK",        // Status Description            mapOf(        // Response header                "Access-Control-Allow-Origin" to "*",
                "Content-Length" to ()
            ),
            byteStream   // Respond to the input stream of content        )
    }

    return (view, request)
}

// Use OkHttp to initiate a network requestprivate fun fetchApiData(url: String): Response {
    val client = OkHttpClient()
    val request = ().url(url).build()

    return (request).execute() // Return the Response object directly}

Key modification points:

  • Set content type and encoding correctly:pass("Content-Type")Get the original responseContent-Type, and pass toWebResourceResponse. Usuallyapplication/json

  • set upContent-Length:pass("Content-Length")Get the length of the response content and pass it to the WebView. If missingContent-Length, some H5 request libraries (such as Axios) may report errors.

  • Returns a valid response stream: You need to make sure()?.byteStream()It is effective. If the network request fails or the stream is empty, you can return an emptyByteArrayInputStream()

  • Set status code and status description: If the request is successful, make sure to return200 OK, otherwise the corresponding status code and description should be returned according to the specific situation.

Checkpoint

  • Ensure that the response flow is effective:make sure()?.byteStream()There is really data, otherwise the H5 side will consider it an invalid response. You can view the status of the response flow through debugging.

  • Correctly set header information:in particularContent-TypeandContent-Length, they are the key to network request processing. Axios relies on these headers to parse the response.

  • Error handling: If an error occurs during the network request process, an appropriate error response should be returned, such as404 Not Foundor500 Internal Server Error, instead of returning an empty response stream directly.

Debugging suggestions

  • Through log debugging, output the status of the OkHttp request, ensurefetchApiDataThe function returnsResponseThe object contains valid data.
  • Check the returned response header on the Axios side to ensureContent-TypeContent-Lengthetc. information is correct.

shouldInterceptRequest When intercepting POST requests, how to obtain the body data of the POST request?

On AndroidWebViewClientPassedshouldInterceptRequestWhen intercepting POST requests and building a custom HTTP request, you first need to manually build the request body (such as fromWebResourceRequestGet the necessary request information in  ), and then useOkHttporHttpURLConnectionSend this POST request.

WebResourceRequestThe POST request body is not provided directly, so the POST request body needs to be obtained and manually constructed. This can be passedrequestHeadersTo build, or pass POST data in advance when sent on the front end (H5).

A complete example of processing a POST request and building a request body:

override fun shouldInterceptRequest(
    view: WebView,
    request: WebResourceRequest
): WebResourceResponse? {
    val url = ()
    val method = 

    if (method == "POST") {
        ("WebView", "Intercepted POST request: $url")

        // Customize the processing of POST requests, build the request body and send it        val responseStream = performCustomHttpPost(url, request)

        // Returns a custom WebResourceResponse        return WebResourceResponse(
            "application/json", // Assume that the return is a JSON response            "UTF-8",
            200, // HTTP status code            "OK", // HTTP status description            mapOf("Access-Control-Allow-Origin" to "*"), // Response header            responseStream // Input stream for response data        )
    }

    return (view, request)
}

// Customize the logic of processing POST requestsfun performCustomHttpPost(url: String, request: WebResourceRequest): InputStream {
    // Build a POST request body (assuming that the POST data sent by the H5 side is in JSON format)    val postData = getPostData(request) // Assume that the request volume data can be extracted here
    // Logging request volume data    ("WebView", "POST request data: $postData")

    // Use OkHttp to send a custom POST request    val client = OkHttpClient()
    val requestBody = (
        ("application/json; charset=utf-8"), // Assume that the request body is JSON data        postData ?: "" // POST requested data    )

    val customRequest = ()
        .url(url)
        .post(requestBody)
        .build()

    // Initiate a request and return the response stream    val response = (customRequest).execute()

    ("WebView", "HTTP Response code: ${()}") // Logging response status code
    return ?.byteStream() ?: ByteArrayInputStream(ByteArray(0))
}

// Get POST data (need to be obtained through front-end or other means)fun getPostData(request: WebResourceRequest): String? {
    // WebView cannot directly obtain POST body data, and the front-end needs to cooperate to pass it through evaluateJavascript or other methods.    // Suppose we get some data from requestHeaders (actually, it can be modified according to your needs)    val contentType = ["Content-Type"]
    ("WebView", "Content-Type: $contentType")

    // Here we return the simulated POST data, which needs to be processed in actual situations.    return "{ \"key\": \"value\" }"
}
Key points:
Get request body data:Android WebView No access provided by itself POST Direct way to request body,Need to cooperate through front-end(like evaluateJavascript)To pass the request body,Or process the simulation request body by yourself。

Manually build POST Request body:use OkHttp of () 方法Manually build POST Request body。

Logging:

pass () Record拦截of URL 和Request body数据,Easy to debug。
Record HTTP Response status code,Check whether the request is successful。
Handle exceptions:like果响应体为空,返回一个空of ByteArrayInputStream(),To ensure WebView Will not crash。

关于获取真实of POST Request body
Android of WebView Get it directly without a built-in mechanism POST Request body,因此需要pass JavaScript and Android Communication,exist H5 Actively POST Data sent to WebView。例like:
// Get the POST request body on the H5 side and pass it to Androidfunction sendPostDataToAndroid(data) {
    if () {
        ((data));
    }
}

Then pass on the Android sideaddJavascriptInterfaceReceive data:

@JavascriptInterface
fun sendPostData(data: String) {
    // Process POST data passed from H5    ("WebView", "Received POST data: $data")
}

at last

In fact, you can try the above method to obtain the post request body parameter content. Of course, there is also a simpler method to take advantage of it. If the number of H5 POST requests is not large, you can communicate with H5 and directly put the request data in the requested url, separate it with specific characters @ in the middle, and then we will process it after getting it.

            // Determine whether it is an XHR request (judged by URL or Accept header)            if ((("/api/") || acceptHeader?.contains("application/json") == true ||
                        headers["X-Requested-With"] == "XMLHttpRequest") && !("html")) {
                ( "Intercepted XHR request: $url")
                // Here you can intercept or modify XHR requests                var respone: Response? = null
                if(method == "POST"){
                    val params = ("@")
                    val test = params[0]                    // Get the body data requested by POST                    val postData = (params[1], StandardCharsets.UTF_8.toString())
                    ("postData = $postData")
                    respone = fetchApiData2(test,method,postData)
                }else if(method == "GET"){
                    respone = fetchApiData(url,method,null)
                }
                val byteStream = respone?.body()?.byteStream() ?: ByteArrayInputStream(ByteArray(0))
                val contentType = respone?.header("Content-Type", "application/json") // Set the default content type                val contentLength = respone?.header("Content-Length", "-1")?.toLong() // Set content length
                ("fetchApiData respone = ${()}")
                return WebResourceResponse(
                    contentType, // Content Type                    "utf-8",     // Encoding format                    200,         // HTTP status code                    "OK",        // Status Description                    mapOf(        // Response header                        "Access-Control-Allow-Origin" to "*",
                        "Content-Length" to ()
                    ),
                    byteStream   // Respond to the input stream of content                )

//                return WebResourceResponse("application/json", "utf-8",respone)
            }
    private fun fetchApiData2(url: String, method: String, postData: String?): Response{
        ("fetchApiData2 = $url + $method + $postData")
        val client = ()
        val requestBody = (
            ("application/json; charset=utf-8"), // Assume that the request body is JSON data            postData ?: "" // POST requested data        )
        val requestBuilder = ()
            .url(url)
            .post(requestBody)
            .build()

        return (requestBuilder).execute()
    }
    // Process according to the request type    private fun fetchApiData(url: String, method: String, postData: Map<String, String>?): Response  {
        ("fetchApiData = $url + $method + $postData")
        val client = ()
        val requestBuilder = ().url(url)

        //Build a request according to the request type        if (method == "POST" && postData != null) {
            val formBody = ()
             { (key, value) -> (key, value) }

            (())
        }

        val request = ()

        return (request).execute() // Return the Response object directly}

Summarize

This is the article about Android webview intercepting H5 interface requests and returning processed data. For more information about Android webview intercepting H5 interface requests, please search for my previous articles or continue browsing the following related articles. I hope everyone will support me in the future!