HarmonyOS鸿蒙Next中在真机上上传图片上传失败的问题
HarmonyOS鸿蒙Next中在真机上上传图片上传失败的问题 各位大佬,我想问一下,我在真机进行调试时,一到上传图片然后显示上传中就无法上传成功是什么原因,我有考虑过是我的代码问题,但是目前找不到哪里错误,我可以请求访问权限等。
开发者您好,您可以参考上传图片的相关demo:如何从图库选择图片并上传到服务器,HarmonyOS 发送请求上传图片的demo,您可以对比参考下您的代码是否需要修改。如果还是未能解决您的问题,麻烦您提供一下您的demo、相关的日志、您的设备版本和IDE版本,感谢您的支持和配合。
更多关于HarmonyOS鸿蒙Next中在真机上上传图片上传失败的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
加个断点调试一下,或加几个log输出,看看执行到哪一步了。
找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17,
背景知识:
楼主首先需要将你得错误的地方给出来,如日志,代码片段。这样大家都有方向对症找问题。上传文件大致如下示例代码
问题解决:
示例代码:
static async uploadFile(
context: common.UIAbilityContext,
filePath: string,
uploadUrl: string
) {
try {
// 1. 读取文件
const file = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY);
const stat = fileIo.statSync(filePath);
const fileSize = stat.size;
// 2. 创建 HTTP 请求
const httpRequest = http.createHttp();
// 3. 组装 form-data
const formData: FormData = {
// 文件字段名(和后端对应,一般是 file 或 upload)
uri: `file://${filePath}`,
name: 'file',
fileName: filePath.split('/').pop(), // 文件名
type: 'application/octet-stream',
// 可加其他字段
userId: "123456",
};
// 4. 发起上传
const response = await httpRequest.request(uploadUrl, {
method: http.RequestMethod.POST,
connectTimeout: 60000,
readTimeout: 60000,
header: {
'Content-Type': 'multipart/form-data',
},
extraData: formData
});
// 5. 结果
if (response.responseCode === 200) {
console.info('上传成功:', response.result);
return JSON.parse(response.result.toString());
} else {
console.error('上传失败 code:', response.responseCode);
return null;
}
} catch (err) {
const e = err as BusinessError;
console.error('上传异常:', e.code, e.message);
return null;
}
}
interface FormData {
uri: string,
name: string,
fileName: string | undefined,
type: string,
userId: string,
}
下面是鸿蒙给出的 api 接口:
这个问题信息有点少,但从 HarmonyOS 开发经验来看:
“图片能选中,显示上传中,但一直上传不成功”
大概率不是权限问题,而是以下几个常见原因。
1. 文件路径问题(最常见)
很多同学在模拟器正常,真机失败。
原因是:
photoAccessHelper.select()
或者
FilePicker
返回的是:
file://media/Photo/xxx
或者
datashare:///...
这样的 URI。
开发者直接把 URI 当成本地文件路径上传:
multipartFile.append(uri)
结果:
模拟器成功
真机失败
因为真机上传框架实际上拿不到文件内容。
建议打印:
console.info(uri)
确认获取到的是:
- URI
- 还是实际文件路径
如果是 URI,需要先通过:
fileUri.getUriFromPath()
或者
fs.open()
读取文件内容再上传。
2. 没有真正读取到文件内容
很多上传 SDK 要求:
ArrayBuffer
或者:
File
而开发者传的是:
字符串路径
例如:
{
file: "/storage/Users/currentUser/..."
}
实际上服务器收到的是:
0KB文件
或者根本没收到文件。
建议检查:
fs.stat()
确认:
size > 0
3. HTTPS证书问题
真机比模拟器严格。
如果服务端:
- 自签名证书
- 过期证书
- TLS配置异常
会出现:
一直上传中
最终失败
建议抓日志:
catch(err=>{
console.error(JSON.stringify(err))
})
重点看:
SSL
TLS
CERT
相关报错。
4. 上传图片太大
HarmonyOS 上传大文件时:
例如:
10MB+
20MB+
HEIF原图
如果直接:
await httpRequest.uploadFile()
可能超时。
特别是:
华为手机拍摄的 HEIF
虽然体积不大:
但解码过程耗时
建议先打印:
fileSize
确认图片大小。
5. HEIF/HEIC格式问题
这个最近特别常见。
HarmonyOS相册拍照默认:
HEIF
服务端很多只支持:
jpg
jpeg
png
上传后:
接口返回失败
开发者误以为没上传成功。
建议打印:
mimeType
例如:
image/heif
image/heic
如果是:
image/heif
建议先转 JPEG。
6. Multipart格式不正确
很多后端要求:
Content-Type:
multipart/form-data
字段名固定:
file
image
avatar
而客户端传:
img
uploadFile
结果:
HTTP 200
但是:
服务端拿不到文件
建议用抓包工具确认。
7. 网络权限问题
确认:
{
"name": "ohos.permission.INTERNET"
}
已经配置。
虽然你说其它接口能访问。
但还是建议确认。
8. 上传接口根本没发出去
建议增加日志:
console.info("开始上传")
upload()
console.info("上传结束")
以及:
onProgress
onHeaderReceive
看看停在哪一步。
9. 真机调试建议
直接看:
hdc shell hilog | grep -i http
或者:
hdc hilog
很多时候日志里直接会看到:
SSL handshake failed
File open failed
Permission denied
Upload timeout
Connection reset
比猜快得多。
如果是在 HarmonyOS NEXT(API 12/13/14/15/23)项目里,我建议优先排查这三个:
① 图片实际是不是 HEIF 格式
② 上传拿到的是 URI 还是真实文件
③ Multipart 文件字段是否正确
这三个问题占真机图片上传失败案例的 80% 以上。
如果能贴出:
- 图片选择代码
- 上传代码
- 接口返回日志
- hilog 错误日志
基本可以直接定位到具体原因。
- 你上传图片到哪里 是oss 还是那块 ,
- 去找一下 你上传的地址 是否有张图
- 上传图片是 给几个打印信息 , 题图 看下信息日志
几个可能原因 1.相册 URI 直接上传,没拷贝沙箱,这样会真机安全拦截,一直转圈
2.用了 http:// 接口,系统明文拦截,无报错。
3.没动态申请 READ_MEDIA ,有权限配置但实际没授权
最好贴一下你的具体报错。大家帮你分析
- 找到上传图片的代码,在上传成功地方打印相应日志(url:用于确定是哪个交易,请求结果,用于判断什么问题)
- 如果找不到,可以先通过 应用文件上传下载 去验证是否确实是自己的代码有问题
- 多打印日志和debug去确定报错信息
上传功能实现
-
导入需要的模块,示例中除去发起请求以及响应错误处理,还需用到CoreFileKit中的fileIo,需导入以下模块。
import { rcp } from '@kit.RemoteCommunicationKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { fileIo } from '@kit.CoreFileKit'; -
定义Session配置,定义一个名为SESSION_CONFIG的对象,用于配置请求会话。配置包括传输超时和安全设置,如远程验证和TLS版本。
let SESSION_CONFIG: rcp.SessionConfiguration = { requestConfiguration: { transfer: { timeout: { connectMs: 6000 } }, security: { remoteValidation: 'skip', tlsOptions: { tlsVersion: 'TlsV1.3' } } } }; -
定义FdReadFile类,用于读取文件描述符(File Descriptor)指向的文件。read方法异步读取指定的ArrayBuffer缓冲区,并返回实际读取的字节数。
class FdReadFile { readonly fd: number; constructor(fd: number) { this.fd = fd; } async read(buffer: ArrayBuffer): Promise<number> { return fileIo.read(this.fd, buffer); } } -
创建会话并打开文件,以只读模式打开一个文件。fileIo.openSync方法返回一个文件描述符,如果打开失败,程序会打印错误信息并返回。
const session = rcp.createSession(SESSION_CONFIG); const file = fileIo.openSync('/data/storage/el1/bundle/entry_test/resources/resfile/upload_file.txt', fileIo.OpenMode.READ_ONLY); if (!file) { console.error('fileIo.openSync failed'); return; } -
读取文件,创建一个FdReadFile实例,并分配一个缓冲区来读取文件。read方法异步执行,等待文件读取完成。
const fdReadFile = new FdReadFile(file.fd); const buffer = new ArrayBuffer(1024 * 1024); // 假设文件大小为1MB await fdReadFile.read(buffer); -
上传文件,使用会话的uploadFromFile方法将文件上传到指定的URL。UploadFromFile构造函数接受一个文件描述符读取文件。上传成功或失败时,会分别打印相应的信息。
session.uploadFromFile('https://httpbin.org/anything', new rcp.UploadFromFile(fdReadFile)) .then((response: rcp.Response) => { console.info(`Upload succeeded: ${response}`) }) .catch((err: BusinessError) => { console.error(`Upload failed: error code is ${err.code}, error data is ${err.data}`) }); -
关闭文件和会话,释放资源。
fileIo.closeSync(file.fd); session.close();
可以用ai助手检测一下。
我怀疑过是我的upload或者是请求写法的问题
在鸿蒙Next真机上传图片失败,常见原因:
- 未在module.json5中声明
ohos.permission.INTERNET及ohos.permission.READ_MEDIA_IMAGES(API 12需动态申请)。 - 使用了
fileUri或files接口路径错误,应改用fileIo.open+Request方式。 - 真机调试需确保HAP签名与权限一致,且网络代理不拦截。检查日志中
errCode进一步定位。
上传失败常见于以下几点,请逐一排查:
-
权限:真机调试需在
module.json5中声明ohos.permission.INTERNET及读写存储权限(如ohos.permission.READ_MEDIA、ohos.permission.WRITE_MEDIA),并在代码中通过requestPermissionsFromUser动态申请,确保授权成功。 -
文件URI:通过系统选择器(如
photoAccessHelper)获取的file://media格式URI,不能直接在网络请求中读取,需转换为应用沙箱路径。可使用fileIo.copyFile将文件复制到context.cacheDir或context.filesDir,再用该路径构造上传数据。 -
请求格式:使用
@ohos.net.http上传时,必须正确构建multipart/form-data。extraData应为ArrayBuffer或string,建议先通过fileIo.readSync读出文件ArrayBuffer,与表单字段一起拼接成multipart格式后提交。 -
网络与日志:检查真机网络连通性,抓取
hilog日志过滤http、fileIo,观察是否有明确错误码(如权限拒绝、文件不存在、超时等)。
聚焦以上几点应能定位问题。

