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

AOSP中NanoHTTPD文件上传遇SocketTimeoutException问题求助

解决NanoHTTPD文件上传超时与API问题

1. 处理SocketTimeoutException:设置服务端超时

IHTTPSession确实没有setReadTimeout方法,超时控制需要在NanoHTTPD服务实例层面配置。在你的NanoHTTPD子类中,通过setSocketTimeout设置更长的超时窗口(比如30秒,适配大文件上传):

public class DeviceWebServer extends NanoHTTPD {
    public DeviceWebServer(int port) {
        super(port);
        // 设置30秒套接字超时,避免文件上传时读取超时
        setSocketTimeout(30000);
    }

    // 重写serve方法及其他业务逻辑
}

2. 修复后端重复解析Body的错误

你的handlePostMethod方法中,开头已调用session.parseBody(params),在/upload分支又重复调用,这会导致Body被重复解析,引发异常或数据丢失。必须删除第二次调用,并优化文件处理逻辑:

private Response handlePostMethod(IHTTPSession session) {
    final Map<String, String> params = new HashMap<>();
    try {
        session.parseBody(params);
    } catch (IOException | ResponseException e) {
        return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, e.getMessage());
    }

    if (params.containsKey("postData") || session.getUri().equalsIgnoreCase("/upload")) {
        switch (session.getUri()) {
            case "/upload":
                Log.d(TAG,"upload case entered");
                try {
                    // 直接从params获取上传文件的临时路径(对应前端FormData的字段名"file")
                    String tempFilePath = params.get("file");
                    if (tempFilePath == null) {
                        return new Response(Response.Status.BAD_REQUEST, MIME_PLAINTEXT, "未检测到上传文件");
                    }

                    File tempFile = new File(tempFilePath);
                    if (!tempFile.exists() || tempFile.length() == 0) {
                        return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "临时文件无效");
                    }

                    // 推荐使用应用私有下载目录替代废弃的Environment.getExternalStorageDirectory()
                    String saveDir = getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
                    // 解析原始文件名:从请求头Content-Disposition中提取
                    String fileName = extractFileName(session);
                    File saveFile = new File(saveDir, fileName != null ? fileName : "uploaded_file");

                    // 复制临时文件到目标路径
                    Files.copy(tempFile.toPath(), saveFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                    // 清理NanoHTTPD生成的临时文件
                    Files.deleteIfExists(tempFile.toPath());

                    Log.d(TAG,"文件上传完成:" + saveFile.getAbsolutePath());
                    return new Response(Response.Status.OK, MIME_PLAINTEXT, "上传成功");
                } catch (Exception e) {
                    Logd("responseJsonError:" + e);
                    return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "上传失败:" + e.getMessage());
                }
            // 其他case逻辑
        }
    }
    return null;
}

// 辅助方法:从请求头提取上传文件的原始文件名
private String extractFileName(IHTTPSession session) {
    String contentType = session.getHeaders().get("content-type");
    if (contentType == null) return null;

    Map<String, String> params = NanoHTTPD.getParameters(contentType);
    return params.get("filename");
}

3. 简化前端上传代码,修复冗余逻辑

前端代码中URL.createObjectURL相关逻辑完全多余,FormData可直接传入文件对象,同时添加文件选择校验:

apkInstallBtn.onclick = () => {
    const fileInput = document.getElementById('fileInput');
    if (!fileInput.files || fileInput.files.length === 0) {
        alert('请先选择要上传的文件');
        return;
    }
    const file = fileInput.files[0];

    const formData = new FormData();
    formData.append('file', file);

    fetch(`http://${ip_address}/upload`, {
        method: 'POST',
        body: formData
    })
    .then(response => {
        if (!response.ok) throw new Error(`HTTP错误:${response.status}`);
        return response.text();
    })
    .then(data => console.log('上传结果:', data))
    .catch(error => console.error('上传失败:', error));
};

关键注意事项

  • 权限适配:Android 10及以上版本,使用getExternalFilesDir无需申请WRITE_EXTERNAL_STORAGE权限;若需写入公共目录,需适配Scoped Storage或申请MANAGE_EXTERNAL_STORAGE权限。
  • NanoHTTPD版本:确保使用v2.3.1及以上版本,旧版本API存在差异(如getFiles()方法获取文件元数据)。
  • 临时文件清理:NanoHTTPD生成的临时文件不会自动删除,上传完成后手动删除可避免存储占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:19:50