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
相关产品推荐
相关产品推荐

