1. 排查流程

我们公司在飞书上开发了一些自建的小程序,主要是前端页面。目前遇到一个问题:有一个 AI 对话聊天的页面地址,在飞书内展示时会出现白屏现象,但在电脑浏览器中访问是正常的。

问题是飞书的环境不像浏览器那样能使用 F12 或开发者工具,导致我无法查看控制台日志或网络请求响应,很难判断白屏的原因(比如资源加载失败、接口报错、CSP限制等)。目前完全没有错误信息,排查起来非常困难。

通过查看 Nginx 的访问日志,可以清楚地看到请求的 User-Agent 信息,注意到其中的 wv 字段,意味着这个页面是在 App 内嵌的 WebView 中加载的,也就是说飞书程序本质上是用 Android 的 WebView 打开的页面并非独立浏览器。

这就给出了一个非常精准的排查思路了,我可以自己写一个简单的 Android 应用,使用 WebView 加载这个出问题的页面地址从而还原飞书内的运行环境。

105.168.4.100 10.201.17.7 10.207.40.5 10.133.179.63:8888 - [19/May/2025:17:58:47 +0800] 304 0 https://filev.uat.tanqidi.com/onlinePreviewNew?code=b2169224c96a77eaa4134e817b8df1e4 0.003 "GET /ekc/apps/knowledge/js/app.c71d643c.js HTTP/1.1" "https://dq.uat.tanqidi.com/ekc/apps/knowledge/chat?xxxxxx" "Mozilla/5.0 (Linux; Android 15; V2458A Build/AP3A.240905.015.A1_V000L1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/126.0.6478.71 Mobile Safari/537.36 Lark/6.1.30 LarkLocale/zh_CN ChannelName/Feishu" "-" 10.133.179.63:8888 304 0.003

1.1 AndroidStudio

WebView 的调试核心就是开启 Chrome 远程调试功能,这样就能像用 F12 一样查看手机中 WebView 加载页面时的 console 日志、network 请求、DOM 渲染、JS 报错等所有调试信息。

import android.os.Bundle
import android.webkit.WebSettings
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private val TAG: String = "WebViewDebug"
    private lateinit var webView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        webView = WebView(this)
        setContentView(webView)

        // 开启 DevTools 调试(可用 chrome://inspect)
        WebView.setWebContentsDebuggingEnabled(true)

        // 设置 WebView 配置
        val settings: WebSettings = webView.settings
        settings.javaScriptEnabled = true
        settings.domStorageEnabled = true
        settings.allowFileAccess = true
        settings.allowContentAccess = true
        settings.userAgentString += " CustomWebView"

        // 载入你要调试的网址
        webView.loadUrl("https://filev.uat.tanqidi.com/onlinePreviewNew?code=b2169224c96a77eaa4134e817b8df1e4")
    }

}

1.2 Chrome

我这边用 Chrome 的 chrome://inspect 连上手机 WebView 之后,点进去虽然能看到页面,但是 DevTools 提示有个“mixed-content(混合内容)被拦截”的错误。

简单说就是:主页面是通过 HTTPS 加载的,但里面很多图片、JS、CSS 等资源却是 HTTP 的。这样一来,WebView 就不让加载这些“非安全”的内容了,直接拦掉了,所以页面看起来可能是空的或者不完整。

最奇怪的是,在电脑浏览器里这些资源都能正常加载,没出啥问题。但是手机上的 WebView 安全策略更严格,它默认就禁止加载这种“HTTPS 页面里塞 HTTP 资源”的情况了。

image-Tfbi.png

image-yEzS.png

image-Amoc.png

1.3 解决方式

因为服务部署在 Kubernetes 上,并且是通过 Ingress 对外暴露的,我选择在 Ingress 层对特定路径 /onlinePreviewNew 做了精准匹配,然后在返回响应之前,先对其中的内容进行了一次全局替换,把所有的 http:// 统一替换成 https://。这样可以确保页面里后续加载的所有资源请求都是安全的 HTTPS,避免了 WebView 中因“混合内容”导致的加载失败问题。最终,这个方式顺利解决了页面空白或加载不完整的问题。

因为时间紧急只能这样做了,但凡时间充裕我都要叫开发人员重新改,目前只能这样了。

image-xIVZ.png

kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: file-online-preview
  namespace: ripples
  annotations:
    kubernetes.io/ingress.class: nginx
    kubesphere.io/alias-name: 在线文件预览
    nginx.ingress.kubernetes.io/server-snippet: |
      location /onlinePreviewNew {
        proxy_pass http://file-online-preview.tanqidi:8888;
        proxy_set_header Host $host;
        sub_filter_once off;
        sub_filter 'http://' 'https://';
        more_set_headers "Content-Type: text/html";
      }
spec:
  tls:
    - hosts:
        - filev.uat.tanqidi.com
      secretName: tanqidi-uat-ssl
  rules:
    - host: filev.uat.tanqidi.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: file-online-preview
                port:
                  number: 8888