鸿蒙 HTTP如何上传表单格式的文件
·
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙(HarmonyOS)开发中,上传表单格式文件(包括multipart/form-data)是一个常见的需求,如:文件上传。
一、基本概念
表单文件上传通常使用multipart/form-data格式,这种格式可以同时上传文件和其他表单字段。在鸿蒙中,可以使用@ohos.net.http模块来实现。
二、核心API介绍
1. 主要类和方法
| 类/方法 | 描述 |
|---|---|
http.createHttp() | 创建HTTP请求对象 |
HttpRequest | HTTP请求类 |
RequestMethod | 请求方法枚举(POST, GET等) |
RequestData | 请求数据类 |
ResponseData | 响应数据类 |
HttpResponse | HTTP响应类 |
2. 文件上传相关方法
// 创建HTTP请求
const httpRequest = http.createHttp();
// 设置请求头
request.setHeader(headerKey, headerValue);
// 上传文件
request.upload(
config: UploadRequest,
callback: AsyncCallback<UploadTask>
): void;
三、完整文件上传实现
1. 简单文件上传示例
import http from '@ohos.net.http';
import fileio from '@ohos.fileio';
import featureAbility from '@ohos.ability.featureAbility';
async function uploadFile(fileUri: string, uploadUrl: string) {
// 1. 创建HTTP请求
const httpRequest = http.createHttp();
// 2. 获取文件信息
const context = featureAbility.getContext();
const filePath = await context.getFilesDir() + '/' + fileUri;
// 3. 准备表单数据
const formData = [
{
name: 'file', // 字段名
filename: 'example.jpg', // 文件名
type: 'image/jpeg', // MIME类型
data: { // 文件数据
uri: filePath,
type: 'file',
}
},
{
name: 'description', // 普通表单字段
value: 'This is a sample file upload' // 字段值
}
];
// 4. 设置请求头
httpRequest.setHeader('Content-Type', 'multipart/form-data');
// 5. 执行上传
try {
const response = await httpRequest.upload(
uploadUrl,
formData,
{ method: http.RequestMethod.POST }
);
console.log('Upload success:', response.result);
return response.result;
} catch (error) {
console.error('Upload failed:', error);
throw error;
} finally {
// 6. 销毁请求
httpRequest.destroy();
}
}
2. 带进度监控的文件上传
import http from '@ohos.net.http';
async function uploadWithProgress(filePath: string, uploadUrl: string) {
const httpRequest = http.createHttp();
// 准备表单数据
const formData = [
{
name: 'file',
filename: 'example.jpg',
type: 'image/jpeg',
data: {
uri: filePath,
type: 'file',
}
}
];
// 创建上传任务
const uploadTask = httpRequest.upload(
uploadUrl,
formData,
{
method: http.RequestMethod.POST,
// 进度回调
progress: (uploaded: number, total: number) => {
const progress = Math.round((uploaded / total) * 100);
console.log(`Upload progress: ${progress}%`);
}
}
);
// 处理上传结果
uploadTask.then((response) => {
console.log('Upload completed:', response.result);
}).catch((error) => {
console.error('Upload error:', error);
});
// 可以取消上传
// uploadTask.abort();
}
3. 多文件上传实现
import http from '@ohos.net.http';
async function uploadMultipleFiles(files: Array<{path: string, name: string}>, uploadUrl: string) {
const httpRequest = http.createHttp();
// 构建多文件表单数据
const formData = files.map(file => ({
name: 'files[]', // 注意数组表示法
filename: file.name,
type: this.getMimeType(file.name),
data: {
uri: file.path,
type: 'file'
}
}));
// 添加其他表单字段
formData.push({
name: 'userId',
value: '12345'
});
try {
const response = await httpRequest.upload(
uploadUrl,
formData,
{ method: http.RequestMethod.POST }
);
console.log('Multi-file upload success:', response.result);
return response.result;
} catch (error) {
console.error('Multi-file upload failed:', error);
throw error;
} finally {
httpRequest.destroy();
}
}
// 获取文件MIME类型
function getMimeType(filename: string): string {
const extension = filename.split('.').pop()?.toLowerCase() || '';
switch (extension) {
case 'jpg':
case 'jpeg':
return 'image/jpeg';
case 'png':
return 'image/png';
case 'gif':
return 'image/gif';
case 'pdf':
return 'application/pdf';
case 'txt':
return 'text/plain';
default:
return 'application/octet-stream';
}
}
四、注意事项
1. 文件路径处理
获取文件路径的正确方式:
import featureAbility from '@ohos.ability.featureAbility';
// 获取应用文件目录
const context = featureAbility.getContext();
const filesDir = await context.getFilesDir();
// 构建完整文件路径
const filePath = filesDir + '/myfile.jpg';
2. 错误处理
完善的错误处理应该包括:
try {
const response = await httpRequest.upload(...);
// 检查HTTP状态码
if (response.responseCode >= 400) {
throw new Error(`Server returned ${response.responseCode}`);
}
// 处理响应数据
const result = JSON.parse(response.result);
} catch (error) {
// 分类处理不同错误
if (error.code === 'ENOENT') {
console.error('File not found');
} else if (error.message.includes('network')) {
console.error('Network error');
} else {
console.error('Unknown error:', error);
}
}
3. 性能优化
对于大文件上传:
// 分块上传大文件
async function chunkedUpload(filePath: string, uploadUrl: string, chunkSize = 1024 * 1024) {
const fileInfo = await fileio.stat(filePath);
const fileSize = fileInfo.size;
let offset = 0;
while (offset < fileSize) {
const end = Math.min(offset + chunkSize, fileSize);
const chunkData = await fileio.read(filePath, { offset, length: end - offset });
const formData = [
{
name: 'file',
filename: 'chunk.dat',
type: 'application/octet-stream',
data: chunkData
},
{
name: 'chunkInfo',
value: JSON.stringify({
fileSize,
offset,
totalChunks: Math.ceil(fileSize / chunkSize)
})
}
];
await uploadChunk(uploadUrl, formData);
offset = end;
}
// 通知服务器完成上传
await notifyUploadComplete(uploadUrl, filePath);
}
五、完整示例:图片上传组件
@Entry
@Component
struct ImageUploader {
@State progress: number = 0;
@State uploadStatus: string = 'Ready';
@State imageUri: string = '';
private httpRequest: http.HttpRequest = http.createHttp();
// 选择图片
async pickImage() {
try {
const result = await picker.pick({
type: picker.PickerType.IMAGE
});
if (result && result.length > 0) {
this.imageUri = result[0].uri;
this.uploadStatus = 'Image selected';
}
} catch (error) {
console.error('Image pick error:', error);
this.uploadStatus = 'Failed to select image';
}
}
// 上传图片
async uploadImage() {
if (!this.imageUri) {
this.uploadStatus = 'No image selected';
return;
}
this.uploadStatus = 'Uploading...';
this.progress = 0;
const formData = [
{
name: 'image',
filename: 'upload.jpg',
type: 'image/jpeg',
data: {
uri: this.imageUri,
type: 'file'
}
},
{
name: 'timestamp',
value: new Date().getTime().toString()
}
];
try {
const uploadTask = this.httpRequest.upload(
'https://example.com/upload',
formData,
{
method: http.RequestMethod.POST,
progress: (uploaded, total) => {
this.progress = Math.round((uploaded / total) * 100);
}
}
);
const response = await uploadTask;
this.uploadStatus = 'Upload completed';
console.log('Server response:', response.result);
} catch (error) {
console.error('Upload error:', error);
this.uploadStatus = 'Upload failed';
}
}
build() {
Column({ space: 20 }) {
if (this.imageUri) {
Image(this.imageUri)
.width(200)
.height(200)
.margin(10)
}
Button('Select Image')
.onClick(() => this.pickImage())
.width('80%')
Button('Upload Image')
.onClick(() => this.uploadImage())
.width('80%')
.enabled(!!this.imageUri)
Progress({ value: this.progress, total: 100 })
.width('80%')
Text(this.uploadStatus)
.fontSize(16)
}
.width('100%')
.padding(20)
}
aboutToDisappear() {
// 组件销毁时释放HTTP资源
this.httpRequest.destroy();
}
}
更多推荐


所有评论(0)