Android向Node.js服务器发送PDF文件无响应问题求助
问题排查与修复:Android文件上传至Node.js服务器无响应
核心问题
你的Android端代码直接将文件流写入HTTP请求体,但Node.js的Multer中间件要求请求采用multipart/form-data格式来解析文件。原请求未按该格式封装,导致Multer无法识别文件,因此服务器没有输出预期日志。
Android端代码修复
修改sendPDF方法,手动构建符合要求的multipart/form-data请求,确保和Node.js端的Multer配置匹配:
public static void sendPDF(Context context, Uri fileUri) { new AsyncTask<Uri, Void, Void>() { @Override protected Void doInBackground(Uri... uris) { Uri uri = uris[0]; try { // 替换为你的实际服务器IP和端口(模拟器用10.0.2.2映射本地localhost) URL url = new URL("http://你的服务器IP:3001/upload"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoInput(true); conn.setDoOutput(true); // 设置multipart/form-data请求头 String boundary = "----WebKitFormBoundary" + System.currentTimeMillis(); conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); conn.setReadTimeout(35000); conn.setConnectTimeout(35000); OutputStream os = conn.getOutputStream(); PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, "UTF-8"), true); // 从Uri解析真实文件名 String fileName = getFileName(context, uri); // 写入文件表单字段(字段名myFile需和Node.js端一致) writer.append("--" + boundary).append("\r\n"); writer.append("Content-Disposition: form-data; name=\"myFile\"; filename=\"" + fileName + "\"").append("\r\n"); writer.append("Content-Type: application/octet-stream").append("\r\n"); writer.append("\r\n").flush(); // 写入文件内容 InputStream inputStream = context.getContentResolver().openInputStream(uri); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } os.flush(); inputStream.close(); // 结束表单 writer.append("\r\n").flush(); writer.append("--" + boundary + "--").append("\r\n").flush(); writer.close(); os.close(); // 打印响应信息用于调试 int responseCode = conn.getResponseCode(); Log.d("UploadDebug", "响应码: " + responseCode); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); StringBuilder response = new StringBuilder(); String line; while ((line = br.readLine()) != null) { response.append(line); } br.close(); Log.d("UploadDebug", "服务器响应: " + response.toString()); conn.disconnect(); } catch (IOException e) { e.printStackTrace(); Log.e("UploadError", "上传失败: " + e.getMessage()); } return null; } }.execute(fileUri); } // 辅助方法:从Uri获取真实文件名 private static String getFileName(Context context, Uri uri) { String result = null; if (uri.getScheme().equals("content")) { Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); try { if (cursor != null && cursor.moveToFirst()) { result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); } } finally { if (cursor != null) cursor.close(); } } if (result == null) { result = uri.getPath(); int cut = result.lastIndexOf('/'); if (cut != -1) result = result.substring(cut + 1); } return result; }
关键修改点
- 添加
Content-Type: multipart/form-data; boundary=xxx请求头,这是Multer解析文件的必要条件 - 表单字段名
myFile和Node.js端upload.single('myFile')严格保持一致 - 补充文件名解析逻辑,避免使用
uri.getPath()返回的虚拟路径 - 添加调试日志,便于确认请求是否到达服务器
Node.js端验证
确保代码已正确引入依赖模块,同时添加错误捕获排查问题:
const express = require('express'); const multer = require('multer'); const fs = require('fs'); const app = express(); const uploadDirectory = 'uploads'; if (!fs.existsSync(uploadDirectory)) { fs.mkdirSync(uploadDirectory); } const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, 'uploads/'); }, filename: (req, file, cb) => { cb(null, file.originalname); } }); const upload = multer({ storage }); // 添加错误捕获的上传路由 app.post('/upload', (req, res) => { upload.single('myFile')(req, res, (err) => { if (err) { console.error('上传错误:', err); return res.status(500).send('上传失败'); } console.log('文件上传成功:', req.file); res.status(200).send('文件上传成功'); }); }); app.listen(3001, () => { console.log('服务器运行在端口3001'); });
额外注意事项
- 确保AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
- 若服务器在本地,Android模拟器需用
10.0.2.2代替本地IP(模拟器环回地址映射主机localhost) - AsyncTask已被标记为过时,可考虑改用Coroutines或OkHttp等现代网络库实现异步请求
内容的提问来源于stack exchange,提问作者abcd1211231
相关产品推荐
相关产品推荐

