You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

三星Galaxy手机Samsung Internet浏览器长时文件下载无提示问题

问题背景与现象

我们开发了一款带有API后端的单页应用,后端会根据请求动态生成文件并返回给前端。部分文件生成耗时极短,部分则需要5秒以上。目前遇到的核心问题:在三星Galaxy手机的Samsung Internet浏览器中,下载生成耗时超5秒的文件时,无法弹出保存提示。文件实际已完成下载,但设备上没有显示任何保存提示,导致用户无法打开或存储文件。

该下载功能在所有测试过的桌面浏览器,以及三星Galaxy手机的Chrome浏览器中均能正常工作,仅在Samsung Internet浏览器中失效。

设备与环境信息

  • 机型:Samsung Galaxy S22+
  • One UI版本:5.1
  • Android版本:13
  • Samsung Internet浏览器版本:21.0.0.41(当前最新版本)

复现步骤

我们提取项目核心代码制作了简易服务端与客户端用于复现问题,步骤如下:

  1. 克隆仓库
  2. 进入server文件夹启动服务端,详细说明见该文件夹下的README
  3. 进入client-js文件夹启动客户端,详细说明见该文件夹下的README
  4. 在电脑端访问http://localhost:8081,可正常下载两个文件:file1即时返回,file2延迟6秒返回
  5. 使用同网络下的三星Galaxy手机,通过Samsung Internet浏览器访问http://your-local-ip-address:8081(替换为电脑实际局域网IP),可正常下载file1,但点击下载file2后(等待6秒)无任何反应,浏览器未弹出打开或保存提示

调试方法

可通过以下步骤调试手机端客户端:

  1. 在三星Galaxy手机的开发者选项中开启USB debugging:
    • 进入Settings > About phone > Software information
    • 连续点击7次Build number
    • 进入Settings > Developer options
    • 开启USB debugging
  2. 使用Google Chrome进行检查:
    • 通过USB线连接手机与电脑
    • 在电脑端Chrome浏览器中访问chrome://inspect/
    • 在手机端确认权限请求
    • 等待设备出现在电脑端Chrome中
    • 在手机端Samsung Internet浏览器中访问http://your-local-ip-address:8081
    • 等待页面出现在电脑端Chrome中,点击inspect

此时会打开新的Chrome窗口显示手机端客户端,可通过F12打开开发者工具分析网络请求与控制台输出,会发现file2已发送至客户端,但无提示弹出。

核心代码片段

服务端核心代码

function serveFile(res, filePath, fileName, contentType) {
  const contentDisposition = `attachment; filename="${encodeURIComponent(fileName)}"`;
  res.setHeader('Content-Disposition', contentDisposition);
  res.setHeader('Access-Control-Expose-Headers', 'Content-Disposition');
  res.setHeader('Content-Type', contentType);
  res.setHeader('Access-Control-Allow-Origin', '*');
  const fileStream = fs.createReadStream(filePath);
  fileStream.pipe(res);
}

const server = http.createServer((req, res) => {
  if (req.url === '/file1') {
    const filePath = path.join(__dirname, 'file1.txt');
    serveFile(res, filePath, 'file1.txt', 'text/plain');
  } else if (req.url === '/file2') {
    setTimeout(() => {
      const filePath = path.join(__dirname, 'file2.txt');
      serveFile(res, filePath, 'file2.txt', 'text/plain');
    }, 6000);
  } else {
    res.statusCode = 404;
    res.end('Not found');
  }
});

JS客户端下载核心代码

async function downloadFile(endpoint) {
  console.log('downloadFile()');
  console.log('endpoint', endpoint);

  const response = await fetch(endpoint);
  console.log('response', response);

  const blob = await response.blob();
  console.log('blob', blob);

  const url = URL.createObjectURL(blob);
  console.log('url', url);

  const contentDispositionHeader = response.headers.get('Content-Disposition');
  const fileName = getFileName(contentDispositionHeader);
  console.log('fileName', fileName);

  const downloadLinkTag = document.createElement('a');
  downloadLinkTag.href = url;
  downloadLinkTag.download = fileName;

  console.log('before click');
  downloadLinkTag.click();
  console.log('after click');

  setTimeout(() => URL.revokeObjectURL(url), 0);
}

function getFileName(contentDispositionHeader) {
  let fileName = contentDispositionHeader
    .split(';')[1]
    .split('=')[1];
  if (fileName.startsWith('"')) {
    fileName = fileName.substring(1, fileName.length - 1);
  }
  if (fileName.endsWith('"')) {
    fileName = fileName.substring(0, fileName.length - 2);
  }
  return decodeURI(fileName);
}

Angular客户端三种下载方式核心代码

private downloadFile(apiUrl: string): void {
  this.http
    .get(apiUrl, { responseType: 'blob', observe: 'response' })
    .subscribe(response => {
      const fileName = this.getFileNameFromHeaders(response.headers);
      console.log('fileName', fileName);

      // 方式1:a标签 + Object URL
      console.log('approach #1');
      const data = response.body;
      if (!data) {
        console.log('no data');
        return;
      }
      console.log('data', data);
      const url = URL.createObjectURL(data);
      console.log('url', url);
      const link = document.createElement('a');
      link.href = url;
      link.download = fileName;
      console.log('before click');
      link.click();
      console.log('after click');
      setTimeout(() => URL.revokeObjectURL(url), 0);

      // 方式2:FileSaver.js
      console.log('approach #2');
      const blob = new Blob([response.body as Blob], {type: 'text/plain'});
      console.log('blob', blob);
      console.log('before saveAs');
      saveAs(blob, fileName);
      console.log('after saveAs');

      // 方式3:FileReader
      console.log('approach #3');
      const reader = new FileReader();
      reader.onloadend = function(e) {
        console.log('reader.result', reader.result);
        const link = document.createElement('a');
        document.body.appendChild(link);
        link.href = reader.result as string;
        link.download = fileName;
        const clickEvent = new MouseEvent('click');
        console.log('before dispatch click event');
        link.dispatchEvent(clickEvent);
        console.log('after dispatch click event');
        setTimeout(()=> {
          document.body.removeChild(link);
        }, 0)
      }
      console.log('response.body', response.body);
      console.log('before readAsDataURL');
      reader.readAsDataURL(response.body as Blob);
      console.log('after readAsDataURL');
    });
}

private getFileNameFromHeaders(headers: HttpHeaders): string {
  const contentDisposition = headers.get('Content-Disposition');
  if (!contentDisposition) {
    return 'unknown.txt';
  }
  let fileName = contentDisposition
    .split(';')[1]
    .split('=')[1];
  if (fileName.startsWith('"')) {
    fileName = fileName.substring(1, fileName.length - 1);
  }
  if (fileName.endsWith('"')) {
    fileName = fileName.substring(0, fileName.length - 2);
  }
  return decodeURI(fileName);
}

仓库中还有一个简易Angular客户端,包含三种下载方式(a标签+Object URL、FileSaver.js、FileReader),均出现相同问题:延迟文件无下载提示。

补充发现

  1. 问题不仅出现在服务端响应超时(>5秒)的场景,在客户端模拟点击a标签前添加超5秒延迟也会触发,推测Samsung Internet浏览器在用户点击下载按钮后有5秒超时限制。
  2. 移除a标签的download属性后,浏览器会显示文件内容,但不符合我们需要弹出保存提示的需求;使用const data = new Blob([data as Blob], {type: 'application/octet-stream'});可触发提示,但会丢失文件名,同样不可行。

疑问咨询

  1. 我们的实现是否存在错误?有无其他方法可让三星Galaxy手机上的下载提示正常显示?
  2. 这是否是Samsung Internet浏览器的bug?

内容的提问来源于stack exchange,提问作者TOG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 03:32:57