HarmonyOS 鸿蒙Next图片上传
HarmonyOS 鸿蒙Next图片上传 HTTP上传图片失败如何解决
【解决方案】
开发者您好,建议排查一下request.UploadConfig参数中的files文件列表,uri属性不正确会导致文件上传失败。uri为文件的本地存储路径,仅支持"internal://cache/",即调用方(传入的context)对应的缓存路径context.cacheDir。示例:internal://cache/path/to/file.txt。
若是不能解决您的问题,请提供下具体报错日志。
更多关于HarmonyOS 鸿蒙Next图片上传的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
以下是我之前测试使用系统提供http库进行文件上传时的代码:
- 文件使用系统提供
DocumentViewPicker选择 - 支持随文件传入额外参数(混合参数)
- 文件必须要先复制到应用沙箱才可以进行上传操作
import { picker } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo as fs } from '@kit.CoreFileKit'
import { http } from '@kit.NetworkKit';
import { JSON } from '@kit.ArkTS';
import { getMimeTypeByFileName } from '../utils/MimeUtil';
@Component
export struct HttpPage {
context = this.getUIContext().getHostContext() as common.UIAbilityContext;
// 请求URL
url = "http://192.168.3.33:8080/file/upload";
// 测试额外参数
@State extraTestParam: string = '';
// 已选择的用户文件名
@State selectedFileName: string = ''
// http响应
@State responseJson: string = ''
build() {
Column({ space: 8 }) {
Text(decodeURI(this.selectedFileName))
Button('选择文件')
.attributeModifier(this.commonButtonAttributeModifier)
.onClick((event: ClickEvent) => {
let documentPicker = new picker.DocumentViewPicker(this.context);
documentPicker.select({
maxSelectNumber: 1
}).then((fileArray: Array<string>) => {
// this.files = ''
// fileArray.forEach((value: string) => this.files += value + ';')
this.selectedFileName = fileArray[0] || ''
})
})
Row({ space: 8 }) {
Text('username:')
TextInput({ placeholder: '额外数据,同文件一起传至后端', text: $$this.extraTestParam })
.width('75%')
}
.width('100%')
Button('上传')
.attributeModifier(this.commonButtonAttributeModifier)
.onClick(() => {
/* 将用户选择的文件复制到应用沙箱内 */
let cacheDir = this.context.cacheDir
// 把文件名称拿出来 复制上传的的时候拼接
const filename: string = this.selectedFileName.split("/").pop() as string
try {
// 需要先将用户文件复制到应用沙箱内
let sourceFile = fs.openSync(this.selectedFileName);
let targetFile = fs.openSync(cacheDir + "/" + filename, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.copyFileSync(sourceFile.fd, targetFile.fd);
fs.closeSync(sourceFile);
fs.closeSync(targetFile);
console.info(`copy file successful, targetPath: ${cacheDir}/${decodeURI(filename)}`);
} catch (e) {
console.info(`copy file failed ${e.message}`);
return;
}
/* *************************** http方式 START *************************** */
let httpRequest = http.createHttp();
// 数据大于5MB请使用[requestInStream](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-http#requestinstream10-2)
httpRequest.request(this.url, {
method: http.RequestMethod.POST,
// 不支持传入Map对象
header: {
// Request 类型
'Content-Type': 'multipart/form-data',
// Response 类型
'Accept': 'application/json',
},
// TODO 当使用POST请求时此字段用于传递请求体内容,具体格式请结合官方文档说明并与服务端协商确定。
// extraData: { 'username': this.extraTestParam },
// 可选,指定返回数据的类型。
// expectDataType: http.HttpDataType.OBJECT,
// 可选,仅当Header中,'content-Type'为'multipart/form-data'时生效,自API 11开始支持该属性。
multiFormDataList: [
{
name: "file",
filePath: `${cacheDir}/${filename}`,
// TODO 这里可以写一个工具类,根据文件名获取MIME类型 getMimeTypeByFileName(filename)
contentType: `application/pdf`
},
// 当使用`multipart/form-data`时,使用此方法传输额外参数
{
name: "username",
data: this.extraTestParam,
contentType: 'text/plain',
}
],
// 连接超时时间(ms)
connectTimeout: 10000
})
.then((response: http.HttpResponse) => {
this.responseJson = JSON.stringify(response)
console.log('请求已完成,Response is: ' + JSON.stringify(response))
})
.catch((error: BusinessError) => {
this.responseJson = JSON.stringify(error)
console.error('请求失败:' + JSON.stringify(error))
})
/* *************************** http方式 END *************************** */
})
TextArea({
placeholder: '这里是Response',
text: $$this.responseJson
})
.focusable(false)
.wordBreak(WordBreak.BREAK_ALL)
}
}
注意:由于传文件的时候’Content-Type’类型为’multipart/form-data’,额外参数需要按照上述代码添加。使用extraData属性无效。
你好,你要贴出报错的信息才能定位!
不然,你复制下官网的示例程序,应该没啥问题,但意义不大,毕竟业务代码环境不同
上传应用文件
开发者可以使用上传下载模块(ohos.request)的上传接口将本地文件上传。文件上传过程通过系统服务代理完成。在api12中,request.agent.create接口增加了设置代理地址的参数,支持设置自定义代理地址。
说明:
· 当前上传应用文件功能。request.uploadFile方式仅支持上传应用缓存文件路径(cacheDir)下的文件,request.agent方式支持上传用户公共文件和应用缓存文件路径下的文件。
· 使用上传下载模块,需声明权限:ohos.permission.INTERNET。
· 上传下载模块不支持Charles、Fiddler等代理抓包工具。
· 上传下载模块接口目前暂不支持子线程调用场景,如TaskPool等。
以下示例代码展示了两种将缓存文件上传至服务器的方法:
// 方式一:request.uploadFile
// pages/xxx.ets
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { BusinessError, request } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
build() {
Row() {
Column() {
Button("上传").onClick(() => {
// 获取应用文件路径
// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let cacheDir = context.cacheDir;
// 新建一个本地应用文件
try {
let file = fs.openSync(cacheDir + '/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.writeSync(file.fd, 'upload file test');
fs.closeSync(file);
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
}
// 上传任务配置项
let files: Array<request.File> = [
//uri前缀internal://cache 对应cacheDir目录
{ filename: 'test.txt', name: 'test', uri: 'internal://cache/test.txt', type: 'txt' }
]
let data: Array<request.RequestData> = [{ name: 'name', value: 'value' }];
let uploadConfig: request.UploadConfig = {
url: 'https://xxx',
header: {
'key1':'value1',
'key2':'value2'
},
method: 'POST',
files: files,
data: data
}
// 将本地应用文件上传至网络服务器
try {
request.uploadFile(context, uploadConfig)
.then((uploadTask: request.UploadTask) => {
uploadTask.on('complete', (taskStates: Array<request.TaskState>) => {
for (let i = 0; i < taskStates.length; i++) {
console.info(`upload complete taskState: ${JSON.stringify(taskStates[i])}`);
}
});
})
.catch((err: BusinessError) => {
console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
})
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
}
})
}
}
}
}
// 方式二:request.agent
// pages/xxx.ets
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { BusinessError, request } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
build() {
Row() {
Column() {
Button("上传").onClick(() => {
// 获取应用文件路径
// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let cacheDir = context.cacheDir;
// 新建一个本地应用文件
let file = fs.openSync(cacheDir + '/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.writeSync(file.fd, 'upload file test');
fs.closeSync(file);
let attachments: Array<request.agent.FormItem> = [{
name: "test",
value: [
{
filename: "test.txt",
path: cacheDir + '/test.txt',
},
]
}];
let config: request.agent.Config = {
action: request.agent.Action.UPLOAD,
url: 'http://xxx',
mode: request.agent.Mode.FOREGROUND,
overwrite: true,
method: "POST",
headers: {
'key1':'value1',
'key2':'value2'
},
data: attachments
};
request.agent.create(context, config).then((task: request.agent.Task) => {
task.start((err: BusinessError) => {
if (err) {
console.error(`Failed to start the upload task, Code: ${err.code} message: ${err.message}`);
return;
}
});
task.on('progress', async(progress) => {
console.warn(`/Request upload status ${progress.state}, uploaded ${progress.processed}`);
})
task.on('completed', async() => {
console.warn(`/Request upload completed`);
//该方法需用户管理任务生命周期,任务结束后调用remove释放task对象
request.agent.remove(task.tid);
})
}).catch((err: BusinessError) => {
console.error(`Failed to create a upload task, Code: ${err.code}, message: ${err.message}`);
});
})
}
}
}
}
HarmonyOS Next图片上传主要使用媒体库管理接口和上传服务。通过@ohos.file.photoAccessHelper获取图片资源,调用PhotoAsset的get接口读取文件数据。上传时使用@ohos.request.upload模块创建上传任务,配置服务器地址和文件参数。支持通过URLSession或HttpClient进行网络传输,可设置进度监听和任务管理。系统提供安全管控机制,确保用户授权后访问媒体文件。注意在module.json5中声明ohos.permission.READ_IMAGEVIDEO权限。
在HarmonyOS Next中处理HTTP图片上传失败时,建议按以下步骤排查:
-
网络权限检查:确保在
module.json5中已配置网络权限:"requestPermissions": [ { "name": "ohos.permission.INTERNET" } ] -
URL与参数验证:
- 确认上传接口URL正确且服务端可用
- 检查请求参数格式(如multipart/form-data)
- 验证文件路径是否有效
-
请求头配置:
let headers = new Map<string, string>(); headers.set('Content-Type', 'multipart/form-data'); -
文件路径处理: 使用
@ohos.file.fs模块获取有效的文件URI:let file = fs.openSync(path, fs.OpenMode.READ_ONLY); -
错误信息捕获: 通过try-catch捕获具体错误码,常见问题包括:
- 网络不可用(错误码200)
- 文件不存在(错误码13900001)
- 权限拒绝(错误码201)
-
服务端兼容性:
- 确认服务端支持选择的HTTP方法(POST/PUT)
- 验证服务端对文件大小和格式的限制
建议使用@ohos.net.http模块进行上传操作,并通过日志输出详细错误信息定位问题。

