Android webview拦截H5的接口哀求并返回处置处罚好的数据 ...

打印 上一主题 下一主题

主题 1022|帖子 1022|积分 3066

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Android webview拦截H5的接口哀求并返回处置处罚好的数据

Android 可以通过 WebView 的 shouldInterceptRequest 方法拦截到 H5 中的网络哀求。这是一个 WebViewClient 中的回调方法,答应开发者在 WebView 发起网络哀求时对其举行处置处罚和修改。
具体利用方法如下:

  • 你必要创建一个自界说的 WebViewClient,并重写 shouldInterceptRequest 方法。
  • 在该方法中,你可以拦截 WebView 发起的网络哀求,并返回一个自界说的响应,或让哀求继续。
  • 该方法在 API 21 (Android 5.0) 及更高版本中引入了两个重载方法:

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

以下是代码示例:
  1. // Kotlin 代码示例
  2. webView.webViewClient = object : WebViewClient() {
  3.     // 对于 API 21 及更高版本
  4.     override fun shouldInterceptRequest(
  5.         view: WebView,
  6.         request: WebResourceRequest
  7.     ): WebResourceResponse? {
  8.         val url = request.url.toString()
  9.         // 这里你可以判断 URL,并根据需要拦截或修改请求
  10.         if (url.contains("your_target_url")) {
  11.             // 可以在这里做一些处理,例如替换请求或返回本地数据
  12.             val inputStream = ... // 自定义输入流
  13.             return WebResourceResponse("text/html", "UTF-8", inputStream)
  14.         }
  15.         // 不拦截,继续请求
  16.         return super.shouldInterceptRequest(view, request)
  17.     }
  18.    
  19.     // 对于 API 11 到 API 20 的设备
  20.     override fun shouldInterceptRequest(
  21.         view: WebView,
  22.         url: String
  23.     ): WebResourceResponse? {
  24.         // 这里处理逻辑类似于上面的代码
  25.         if (url.contains("your_target_url")) {
  26.             // 自定义处理逻辑
  27.             val inputStream = ...
  28.             return WebResourceResponse("text/html", "UTF-8", inputStream)
  29.         }
  30.         return super.shouldInterceptRequest(view, url)
  31.     }
  32. }
复制代码
在 shouldInterceptRequest 方法中,你可以返回一个 WebResourceResponse 对象,来改变或替换原始的网络哀求,也可以通过默认实现让哀求继续执行。
获取网络接口哀求的数据(如 API 哀求的响应),然后将其返回给 H5,
有以下几种方式可以思量:
1. 拦截哀求并手动发起哀求

你可以通过 shouldInterceptRequest 方法拦截 WebView 的 API 哀求,本身在 Java 或 Kotlin 中利用 HttpURLConnection 或 OkHttp 发起网络哀求,处置处罚完响应后,再将响应数据通报给 H5。
示例代码:
  1. webView.webViewClient = object : WebViewClient() {
  2.     override fun shouldInterceptRequest(
  3.         view: WebView,
  4.         request: WebResourceRequest
  5.     ): WebResourceResponse? {
  6.         val url = request.url.toString()
  7.         // 判断是否是需要拦截的接口请求
  8.         if (url.contains("your_api_endpoint")) {
  9.             // 通过 OkHttp 或 HttpURLConnection 发起请求
  10.             val response = fetchApiData(url)
  11.             // 将获取的响应内容传递给 H5
  12.             view.post {
  13.                 view.evaluateJavascript("javascript:handleApiResponse('${response}')", null)
  14.             }
  15.             // 返回一个空响应或自定义内容
  16.             return WebResourceResponse("application/json", "UTF-8", null)
  17.         }
  18.         return super.shouldInterceptRequest(view, request)
  19.     }
  20.     // 使用 OkHttp 发起网络请求(可以根据你的需求选择合适的网络库)
  21.     private fun fetchApiData(url: String): String {
  22.         // 简单 OkHttp 请求示例
  23.         val client = OkHttpClient()
  24.         val request = Request.Builder().url(url).build()
  25.         client.newCall(request).execute().use { response ->
  26.             return response.body?.string() ?: ""
  27.         }
  28.     }
  29. }
复制代码
在这个例子中,shouldInterceptRequest 会拦截指定的网络哀求,然后用 OkHttp 发起哀求,并将获取的响应数据通过 evaluateJavascript 方法传回到 WebView 中的 H5 页面。
2. 通过 WebView 和 H5 的 JavaScript 通信

另一种方式是通过 WebView 的 addJavascriptInterface 方法,将 Android 代码和 H5 举行通信。当 Android 发起哀求后,可以通过接口将数据通报给 H5。

  • 在 H5 中界说一个 JavaScript 函数,用于接收数据:
  1. function handleApiResponse(response) {
  2.     console.log("API Response: ", response);
  3.     // 这里可以对响应进行处理,渲染到页面等
  4. }
复制代码
       2. 在 Android 端:
  1. webView.addJavascriptInterface(object {
  2.     @JavascriptInterface
  3.     fun sendDataToH5(data: String) {
  4.         // 发送数据到 H5
  5.         webView.evaluateJavascript("javascript:handleApiResponse('$data')", null)
  6.     }
  7. }, "AndroidInterface")
  8. webView.webViewClient = object : WebViewClient() {
  9.     override fun shouldInterceptRequest(
  10.         view: WebView,
  11.         request: WebResourceRequest
  12.     ): WebResourceResponse? {
  13.         val url = request.url.toString()
  14.         
  15.         if (url.contains("your_api_endpoint")) {
  16.             val response = fetchApiData(url)
  17.             
  18.             // 通过 JavaScript 接口传递数据到 H5
  19.             view.post {
  20.                 view.evaluateJavascript("javascript:AndroidInterface.sendDataToH5('${response}')", null)
  21.             }
  22.             
  23.             return WebResourceResponse("application/json", "UTF-8", null)
  24.         }
  25.         return super.shouldInterceptRequest(view, request)
  26.     }
  27. }
复制代码
这种必要思量到H5 发过来的网络接口哀求类型吗?post 还是 get

是的,在利用 shouldInterceptRequest 拦截 H5 发过来的网络哀求时,必要思量哀求的类型(GET 或 POST)。这是由于 GET 和 POST 哀求的处置处罚方式不同,尤其是 POST 哀求,它带有哀求体(body)数据,而 GET 哀求通常只包含 URL 参数。
shouldInterceptRequest 可以帮助你拦截哀求,但对于 POST 哀求的处置处罚,必要特别注意提取和利用哀求体。
如何区分 GET 和 POST 哀求?

在 API 21 及更高版本中,shouldInterceptRequest 方法中的 WebResourceRequest 对象包含了更多信息,可以通过它的 getMethod() 方法来区分哀求类型。
  1. override fun shouldInterceptRequest(
  2.     view: WebView,
  3.     request: WebResourceRequest
  4. ): WebResourceResponse? {
  5.     val url = request.url.toString()
  6.     val method = request.method  // 获取请求方法,如 GET 或 POST
  7.     // 根据请求类型处理
  8.     if (method == "POST") {
  9.         // 获取 POST 请求的 body(在 Android 的 WebView 中,直接获取 POST body 是不支持的,除非使用特定工具)
  10.         // 自定义逻辑处理 POST 请求
  11.     } else if (method == "GET") {
  12.         // 处理 GET 请求
  13.     }
  14.     return super.shouldInterceptRequest(view, request)
  15. }
复制代码
处置处罚 POST 哀求

Android 的 shouldInterceptRequest 本身不直接提供获取 POST 哀求体的功能。不过你可以利用其他方式来处置处罚,比方通过在 JS 中提前将哀求体通过某种方式通报给 Android。
方法 1:利用 evaluateJavascript 通报 POST 哀求数据

你可以让 H5 页面在发出 POST 哀求前,通过 JavaScript 提前将 POST 哀求的数据发送到 WebView。然后 Android 端可以拦截并处置处罚这些数据。

  • 在 H5 中拦截和通报 POST 哀求数据:
    1. function interceptAndSendPostData(url, data) {
    2.     // 调用 Android 接口,将数据传递给 WebView
    3.     AndroidInterface.sendPostData(url, JSON.stringify(data));
    4.    
    5.     // 继续发起 POST 请求
    6.     fetch(url, {
    7.         method: "POST",
    8.         body: JSON.stringify(data),
    9.         headers: {
    10.             "Content-Type": "application/json"
    11.         }
    12.     }).then(response => response.json())
    13.       .then(data => console.log(data));
    14. }
    复制代码
  • 在 Android 中接收 POST 数据:
    1. webView.addJavascriptInterface(object {
    2.     @JavascriptInterface
    3.     fun sendPostData(url: String, data: String) {
    4.         // 这里可以处理传递过来的 POST 请求数据
    5.         Log.d("WebView", "POST 请求 URL: $url, 数据: $data")
    6.     }
    7. }, "AndroidInterface")
    复制代码
方法 2:通过自界说网络层发送 POST 哀求

另一种方式是在 shouldInterceptRequest 中拦截 POST 哀求后,手动发起 HTTP 哀求,处置处罚哀求体和响应数据。固然 shouldInterceptRequest 本身不直接提供哀求体,但你可以在 H5 页面中通过 JavaScript 提前将 POST 哀求体通报给 Android,或者通过其他网络拦截方式处置处罚(比方利用 OkHttp 的拦截器)。
  1. override fun shouldInterceptRequest(
  2.     view: WebView,
  3.     request: WebResourceRequest
  4. ): WebResourceResponse? {
  5.     val url = request.url.toString()
  6.     val method = request.method  // 获取请求方法,如 GET 或 POST
  7.     if (method == "POST") {
  8.         // 自定义发起 HTTP 请求,处理 POST 请求体和响应
  9.         val response = performCustomHttpPost(url, request)
  10.         return WebResourceResponse("application/json", "UTF-8", response)
  11.     }
  12.     return super.shouldInterceptRequest(view, request)
  13. }
  14. fun performCustomHttpPost(url: String, request: WebResourceRequest): InputStream {
  15.     // 使用 OkHttp 或 HttpURLConnection 发送自定义 POST 请求
  16.     val client = OkHttpClient()
  17.     val requestBody = ... // 构建请求体
  18.     val request = Request.Builder()
  19.         .url(url)
  20.         .post(requestBody)
  21.         .build()
  22.     val response = client.newCall(request).execute()
  23.     return response.body?.byteStream() ?: ByteArrayInputStream(ByteArray(0))
  24. }
复制代码
小结



  • GET 哀求:你可以直接通过 URL 和哀求头信息来拦截和处置处罚。
  • POST 哀求:必要特别处置处罚哀求体数据。你可以通过 JavaScript 提前将 POST 哀求数据通报给 WebView,或通过手动发起 HTTP 哀求处置处罚 POST 哀求及其响应。
shouldInterceptRequest 能判断出来网络哀求的类型吗?好比script xhr 等

shouldInterceptRequest 本身并不能直接判断网络哀求的具体类型(如 script、xhr 等),由于它没有提供一个字段明确表明哀求是某种类型的资源(如 JavaScript 文件、XHR 哀求等)。不过,你可以通过哀求的 URL哀求头信息 来推断哀求的类型。
在 API 21 及以上的 Android 版本中,WebResourceRequest 对象提供了丰富的信息,包罗哀求的 URL、哀求方法(GET、POST 等)、哀求头等,可以根据这些信息推断哀求类型。
如何通过 URL 和哀求头判断哀求类型?


  • 通过 URL 后缀

    • 假如哀求的 URL 以 .js 结尾,通常可以以为这是一个 script 哀求。
    • 假如 URL 中包含 /api/ 或类似的标识符,可能是 xhr 哀求。
    • CSS 通常以 .css 结尾,图片文件以 .jpg、.png、.gif 结尾等。

  • 通过哀求头: 你可以通过哀求的头部来推断哀求的类型,比方 Accept 头部通常指示客户端期望接收到的数据类型。

    • Accept: application/json 常用于 xhr 哀求。
    • Accept: text/css 表示哀求 CSS 文件。
    • Accept: application/javascript 或 Accept: text/javascript 用于 JavaScript 文件哀求。

代码示例:如何通过 URL 和哀求头推断哀求类型

  1. override fun shouldInterceptRequest(
  2.     view: WebView,
  3.     request: WebResourceRequest
  4. ): WebResourceResponse? {
  5.     val url = request.url.toString()
  6.     val headers = request.requestHeaders
  7.     val acceptHeader = headers["Accept"]  // 获取 Accept 头
  8.     // 判断是否为脚本请求 (script)
  9.     if (url.endsWith(".js") || acceptHeader?.contains("application/javascript") == true) {
  10.         Log.d("WebView", "拦截到脚本请求: $url")
  11.         // 在此可以拦截或修改脚本请求
  12.     }
  13.     // 判断是否为 XHR 请求 (通过 URL 或 Accept 头判断)
  14.     if (url.contains("/api/") || acceptHeader?.contains("application/json") == true) {
  15.         Log.d("WebView", "拦截到 XHR 请求: $url")
  16.         // 在此可以拦截或修改 XHR 请求
  17.     }
  18.     // 判断是否为 CSS 请求
  19.     if (url.endsWith(".css") || acceptHeader?.contains("text/css") == true) {
  20.         Log.d("WebView", "拦截到 CSS 请求: $url")
  21.         // 在此可以拦截或修改 CSS 请求
  22.     }
  23.     // 其他资源类型的请求
  24.     Log.d("WebView", "其他类型的请求: $url")
  25.    
  26.     return super.shouldInterceptRequest(view, request)
  27. }
复制代码
常见资源类型的判断方式



  • JavaScript 文件哀求 (script)

    • 通过 URL 判断:url.endsWith(".js")
    • 通过 Accept 头判断:application/javascript 或 text/javascript

  • XHR 哀求

    • 通过 URL 规则判断:假如 URL 中包含 /api/、/ajax/ 或其他常见的 API 路径。
    • 通过 Accept 头判断:application/json

  • CSS 文件哀求

    • 通过 URL 判断:url.endsWith(".css")
    • 通过 Accept 头判断:text/css

  • 图片文件哀求

    • 通过 URL 判断:url.endsWith(".jpg")、.png、.gif 等
    • 通过 Accept 头判断:image/*

  • HTML 页面哀求

    • 通过 Accept 头判断:text/html

小结

固然 shouldInterceptRequest 没有直接提供资源类型的字段,但你可以通过 URL 的格式和哀求头(特别是 Accept 头)来推断哀求的类型,从而拦截特定的资源哀求。
script xhr font png preflight 分别是什么,应该怎么判断呢?都可以通过 val acceptHeader = headers["Accept"] 来举行判断吗?

Accept 头在 HTTP 哀求中指示客户端盼望接收的响应数据类型,它确实能在一些情况下帮助我们判断哀求的资源类型。但并不是所有类型的哀求都会明确利用 Accept 头。因此,我们必要结合 URL哀求头 的其他信息(如 Content-Type、Access-Control-Request-Method 等)来举行判断。
1. Script(JavaScript 哀求)

JavaScript 哀求是用来加载 .js 文件的资源哀求。
判断依据:


  • URL 后缀:通常 .js 文件后缀。
  • Accept 头:application/javascript 或 text/javascript。
  1. if (url.endsWith(".js") || acceptHeader?.contains("application/javascript") == true || acceptHeader?.contains("text/javascript") == true) {
  2.     Log.d("WebView", "拦截到 JavaScript 请求: $url")
  3. }
复制代码

2. XHR 哀求(XMLHttpRequest / Fetch 哀求)

XHR 哀求通常用于 AJAX 哀求或利用 Fetch API 的异步网络哀求。
判断依据:


  • URL 规则:API 哀求通常有特定路径,比方 /api/、/ajax/ 等。
  • Accept 头:application/json(假如返回 JSON 数据)。
  • 哀求头:XHR 哀求会带有 X-Requested-With: XMLHttpRequest 头部(但不是所有情况都有此头部)。
  1. if (url.contains("/api/") || acceptHeader?.contains("application/json") == true || headers["X-Requested-With"] == "XMLHttpRequest") {
  2.     Log.d("WebView", "拦截到 XHR 请求: $url")
  3. }
复制代码

3. Font 哀求(字体文件哀求)

字体文件通常以 .woff、.woff2、.ttf、.otf 等后缀结尾。
判断依据:


  • URL 后缀:.woff、.woff2、.ttf、.otf。
  • Accept 头:font/* 或 application/font-woff。
  1. if (url.endsWith(".woff") || url.endsWith(".woff2") || url.endsWith(".ttf") || url.endsWith(".otf") || acceptHeader?.contains("font/") == true) {
  2.     Log.d("WebView", "拦截到字体文件请求: $url")
  3. }
复制代码

4. PNG 哀求(图片哀求)

图片哀求通常包罗 .png、.jpg、.gif 等格式。
判断依据:


  • URL 后缀:图片文件通常以 .png、.jpg、.jpeg、.gif 结尾。
  • Accept 头:image/*。
  1. if (url.endsWith(".png") || url.endsWith(".jpg") || url.endsWith(".jpeg") || url.endsWith(".gif") || acceptHeader?.contains("image/") == true) {
  2.     Log.d("WebView", "拦截到图片请求: $url")
  3. }
复制代码

5. Preflight 哀求

Preflight 哀求是 CORS 哀求的一部分,通常在跨域 POST、PUT、DELETE 哀求前发送,以确定服务器是否答应该哀求。Preflight 哀求利用 OPTIONS 方法发起。
判断依据:


  • HTTP 方法:OPTIONS(Preflight 哀求是 OPTIONS 方法的哀求)。
  • 哀求头:包含 Access-Control-Request-Method 和 Access-Control-Request-Headers。
  1. if (request.method == "OPTIONS" && headers.containsKey("Access-Control-Request-Method")) {
  2.     Log.d("WebView", "拦截到 Preflight 请求: $url")
  3. }
复制代码

结合 URL 和 Accept 头举行判断

总结不同哀求类型的判断依据:
哀求类型URL 后缀Accept 头其他哀求头信息Script (JavaScript).jsapplication/javascript, text/javascriptXHR (AJAX)/api/, /ajax/application/jsonX-Requested-With: XMLHttpRequestFont (字体).woff, .woff2, .ttf, .otffont/*, application/font-woffImage (图片).png, .jpg, .jpeg, .gifimage/*Preflight (CORS)OPTIONS 方法,Access-Control-Request-Method 小结



  • Accept 头可以帮助判断哀求类型,但并不是所有哀求都明确利用它。
  • 根据 URL 后缀、哀求方法、其他哀求头(如 X-Requested-With、Access-Control-Request-Method)结合判断能更准确辨认不同类型的哀求。
返回的响应不符合预期的格式,怎么处置处罚

出现 AxiosError: Network Error, Code: ERR_NETWORK 错误,通常是由于 WebView 在处置处罚拦截的网络哀求时,返回的响应不符合预期的格式,或者某些必要的头信息缺失。这里有几个常见的原因及解决办法:
问题可能的原因:


  • 响应流的格式或处置处罚错误: 你正在返回 response.body()?.byteStream(),但是你还必要确保整个 WebResourceResponse 对象是准确设置的,尤其是内容类型、编码格式以及响应头信息。任何一项堕落都可能导致 H5(比方通过 Axios)以为网络哀求失败。
  • 响应头缺失或不完备: WebResourceResponse 必要提供一些关键的响应头,好比 Content-Type 和 Content-Length,这些头在网络哀求处置处罚中是必须的。H5 哀求的 Axios 必要明确知道响应的长度和类型,否则会以为响应无效。
  • 返回的流不完备或被提前关闭: 假如返回的流有问题,好比它被提前关闭或者有其他异常情况,可能导致 Axios 在处置处罚时报错。
如何准确返回自界说响应

确保你利用 WebResourceResponse 构建响应时,包罗了所有必要的头信息和流数据。
修改代码示例

  1. override fun shouldInterceptRequest(
  2.     view: WebView,
  3.     request: WebResourceRequest
  4. ): WebResourceResponse? {
  5.     val url = request.url.toString()
  6.    
  7.     if (url.contains("your_api_endpoint")) {
  8.         // 发起网络请求获取数据
  9.         val response = fetchApiData(url)
  10.         
  11.         // 处理返回的响应流
  12.         val byteStream = response.body?.byteStream() ?: ByteArrayInputStream(ByteArray(0))
  13.         val contentType = response.header("Content-Type", "application/json") // 设置默认内容类型
  14.         val contentLength = response.header("Content-Length", "-1").toLong() // 设置内容长度
  15.         
  16.         // 构建 WebResourceResponse 并返回给 WebView
  17.         return WebResourceResponse(
  18.             contentType, // 内容类型
  19.             "utf-8",     // 编码格式
  20.             200,         // HTTP 状态码
  21.             "OK",        // 状态描述
  22.             mapOf(        // 响应头
  23.                 "Access-Control-Allow-Origin" to "*",
  24.                 "Content-Length" to contentLength.toString()
  25.             ),
  26.             byteStream   // 响应内容的输入流
  27.         )
  28.     }
  29.     return super.shouldInterceptRequest(view, request)
  30. }
  31. // 使用 OkHttp 发起网络请求
  32. private fun fetchApiData(url: String): Response {
  33.     val client = OkHttpClient()
  34.     val request = Request.Builder().url(url).build()
  35.     return client.newCall(request).execute() // 直接返回 Response 对象
  36. }
复制代码
关键修改点:


  • 准确设置内容类型和编码:通过 response.header("Content-Type") 获取原始响应的 Content-Type,并通报给 WebResourceResponse。通常是 application/json。
  • 设置 Content-Length:通过 response.header("Content-Length") 获取响应内容的长度,并将其通报给 WebView。假如缺少 Content-Length,某些 H5 哀求库(如 Axios)可能会报错。
  • 返回有用的响应流:你必要确保 response.body()?.byteStream() 是有用的。假如网络哀求失败或流为空,你可以返回一个空的 ByteArrayInputStream()。
  • 设置状态码和状态形貌:假如哀求乐成,确保返回 200 OK,否则应根据具体情况返回相应的状态码和形貌。
检查点


  • 确保响应流有用:确保 response.body()?.byteStream() 真的有数据,否则 H5 端会以为是无效的响应。你可以通过调试查看响应流的状态。
  • 准确设置头信息:特别是 Content-Type 和 Content-Length,它们是网络哀求处置处罚的关键。Axios 依赖这些头信息来解析响应。
  • 错误处置处罚:假如在网络哀求过程中发生错误,应返回合适的错误响应,好比 404 Not Found 或 500 Internal Server Error,而不是直接返回空的响应流。
调试发起



  • 通过日志调试输出 OkHttp 哀求的状态,确保 fetchApiData 函数返回的 Response 对象中包含有用的数据。
  • 在 Axios 端检查返回的响应头,确保 Content-Type、Content-Length 等信息是准确的。
shouldInterceptRequest 拦截POST哀求的时候,如何获取POST 哀求的 body 数据?

在 Android 的 WebViewClient 中通过 shouldInterceptRequest 拦截 POST 哀求并构建自界说的 HTTP 哀求时,起首必要手动构建哀求体(如从 WebResourceRequest 中获取必要的哀求信息),然后利用 OkHttp 或 HttpURLConnection 来发送这个 POST 哀求。
WebResourceRequest 不直接提供 POST 哀求体,因此要获取并手动构建 POST 哀求体。这可以通过 requestHeaders 来构建,或在前端(H5)发送时提前通报 POST 数据。
处置处罚 POST 哀求并构建哀求体的完备示例:

  1. override fun shouldInterceptRequest(
  2.     view: WebView,
  3.     request: WebResourceRequest
  4. ): WebResourceResponse? {
  5.     val url = request.url.toString()
  6.     val method = request.method
  7.     if (method == "POST") {
  8.         Log.d("WebView", "拦截到 POST 请求: $url")
  9.         // 自定义处理 POST 请求,构建请求体并发送
  10.         val responseStream = performCustomHttpPost(url, request)
  11.         // 返回自定义的 WebResourceResponse
  12.         return WebResourceResponse(
  13.             "application/json", // 假设返回的是 JSON 响应
  14.             "UTF-8",
  15.             200, // HTTP 状态码
  16.             "OK", // HTTP 状态描述
  17.             mapOf("Access-Control-Allow-Origin" to "*"), // 响应头
  18.             responseStream // 响应数据的输入流
  19.         )
  20.     }
  21.     return super.shouldInterceptRequest(view, request)
  22. }
  23. // 自定义处理 POST 请求的逻辑
  24. fun performCustomHttpPost(url: String, request: WebResourceRequest): InputStream {
  25.     // 构建 POST 请求体(假设 H5 端发送的 POST 数据是 JSON 格式)
  26.     val postData = getPostData(request) // 假设这里可以提取请求体数据
  27.     // 日志记录请求体数据
  28.     Log.d("WebView", "POST 请求数据: $postData")
  29.     // 使用 OkHttp 发送自定义的 POST 请求
  30.     val client = OkHttpClient()
  31.     val requestBody = RequestBody.create(
  32.         MediaType.parse("application/json; charset=utf-8"), // 假设请求体是 JSON 数据
  33.         postData ?: "" // POST 请求的数据
  34.     )
  35.     val customRequest = Request.Builder()
  36.         .url(url)
  37.         .post(requestBody)
  38.         .build()
  39.     // 发起请求并返回响应流
  40.     val response = client.newCall(customRequest).execute()
  41.     Log.d("WebView", "HTTP 响应码: ${response.code()}") // 日志记录响应状态码
  42.     return response.body?.byteStream() ?: ByteArrayInputStream(ByteArray(0))
  43. }
  44. // 获取 POST 数据(需要通过前端传递或其他方式获取)
  45. fun getPostData(request: WebResourceRequest): String? {
  46.     // WebView 无法直接获取 POST body 数据,需要前端配合通过 evaluateJavascript 或其他方式传递
  47.     // 假设我们从 requestHeaders 中获取部分数据(实际可以根据你的需求进行修改)
  48.     val contentType = request.requestHeaders["Content-Type"]
  49.     Log.d("WebView", "Content-Type: $contentType")
  50.     // 这里返回模拟的 POST 数据,实际情况下需要处理真实的请求体
  51.     return "{ "key": "value" }"
  52. }
复制代码
  1. 关键点:
  2. 获取请求体数据:Android WebView 本身不提供获取 POST 请求体的直接方式,需要通过前端协作(如 evaluateJavascript)来传递请求体,或者自行处理模拟请求体。
  3. 手动构建 POST 请求体:使用 OkHttp 的 RequestBody.create() 方法手动构建 POST 请求体。
  4. 记录日志:
  5. 通过 Log.d() 记录拦截的 URL 和请求体数据,便于调试。
  6. 记录 HTTP 响应状态码,查看请求是否成功。
  7. 处理异常情况:如果响应体为空,返回一个空的 ByteArrayInputStream(),以确保 WebView 不会崩溃。
  8. 关于获取真实的 POST 请求体
  9. Android 的 WebView 没有内置机制直接获取 POST 请求体,因此需要通过 JavaScript 与 Android 通信,在 H5 端主动将 POST 数据发送给 WebView。例如:
复制代码
  1. // 在 H5 端获取 POST 请求体并传递给 Android
  2. function sendPostDataToAndroid(data) {
  3.     if (window.AndroidInterface) {
  4.         window.AndroidInterface.sendPostData(JSON.stringify(data));
  5.     }
  6. }
复制代码
然后在 Android 端通过 addJavascriptInterface 接收数据:
  1. @JavascriptInterface
  2. fun sendPostData(data: String) {
  3.     // 处理从 H5 传递过来的 POST 数据
  4.     Log.d("WebView", "收到的 POST 数据: $data")
  5. }
复制代码
最后

其实获取post哀求体参数内容上述的方法可以实验一下,当然,还有一种更简单的取巧的方法,假如H5 POST哀求数目不是很多的话,可以和H5沟通好,直接把哀求数据放在哀求的url中,中心通过特定字符@隔开,然后我们拿到后举行处置处罚,
  1.             // 判断是否为 XHR 请求 (通过 URL 或 Accept 头判断)
  2.             if ((url.contains("/api/") || acceptHeader?.contains("application/json") == true ||
  3.                         headers["X-Requested-With"] == "XMLHttpRequest") && !url.endsWith("html")) {
  4.                 LogUtils.i( "拦截到 XHR 请求: $url")
  5.                 // 在此可以拦截或修改 XHR 请求
  6.                 var respone: Response? = null
  7.                 if(method == "POST"){
  8.                     val params = url.split("@")
  9.                     val test = params[0]                    // 获取 POST 请求的 body 数据
  10.                     val postData = URLDecoder.decode(params[1], StandardCharsets.UTF_8.toString())
  11.                     LogUtils.i("postData = $postData")
  12.                     respone = fetchApiData2(test,method,postData)
  13.                 }else if(method == "GET"){
  14.                     respone = fetchApiData(url,method,null)
  15.                 }
  16.                 val byteStream = respone?.body()?.byteStream() ?: ByteArrayInputStream(ByteArray(0))
  17.                 val contentType = respone?.header("Content-Type", "application/json") // 设置默认内容类型
  18.                 val contentLength = respone?.header("Content-Length", "-1")?.toLong() // 设置内容长度
  19.                 LogUtils.i("fetchApiData respone = ${respone.toString()}")
  20.                 return WebResourceResponse(
  21.                     contentType, // 内容类型
  22.                     "utf-8",     // 编码格式
  23.                     200,         // HTTP 状态码
  24.                     "OK",        // 状态描述
  25.                     mapOf(        // 响应头
  26.                         "Access-Control-Allow-Origin" to "*",
  27.                         "Content-Length" to contentLength.toString()
  28.                     ),
  29.                     byteStream   // 响应内容的输入流
  30.                 )
  31. //                return WebResourceResponse("application/json", "utf-8",respone)
  32.             }
复制代码
  1.     private fun fetchApiData2(url: String, method: String, postData: String?): Response{
  2.         LogUtils.i("fetchApiData2 = $url + $method + $postData")
  3.         val client = UnsafeOkHttpClient.unsafeOkHttpClient.build()
  4.         val requestBody = RequestBody.create(
  5.             MediaType.parse("application/json; charset=utf-8"), // 假设请求体是 JSON 数据
  6.             postData ?: "" // POST 请求的数据
  7.         )
  8.         val requestBuilder = Request.Builder()
  9.             .url(url)
  10.             .post(requestBody)
  11.             .build()
  12.         return client.newCall(requestBuilder).execute()
  13.     }
复制代码
  1.     // 根据请求类型进行处理
  2.     private fun fetchApiData(url: String, method: String, postData: Map<String, String>?): Response  {
  3.         LogUtils.i("fetchApiData = $url + $method + $postData")
  4.         val client = UnsafeOkHttpClient.unsafeOkHttpClient.build()
  5.         val requestBuilder = Request.Builder().url(url)
  6.         // 根据请求类型构建请求
  7.         if (method == "POST" && postData != null) {
  8.             val formBody = FormBody.Builder()
  9.             postData.forEach { (key, value) -> formBody.add(key, value) }
  10.             requestBuilder.post(formBody.build())
  11.         }
  12.         val request = requestBuilder.build()
  13.         return client.newCall(request).execute() // 直接返回 Response 对象
  14. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

慢吞云雾缓吐愁

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表