5月28日 02:35

cURL 如何实现文件上传功能?

cURL 支持多种文件上传方式,核心区别在于 Content-Type 和请求体的组织形式。面试中最高频考察的是 -F 表单上传和 -T PUT 上传的区别。

-F 表单上传(multipart/form-data)

-F 是最常用的上传方式,模拟浏览器表单提交,自动设置 Content-Type: multipart/form-data

bash
# 基本上传 curl -X POST https://api.example.com/upload \ -F "file=@/path/to/document.pdf" # 指定 MIME 类型(服务器可能根据类型做不同处理) curl -X POST https://api.example.com/upload \ -F "file=@/path/to/image.png;type=image/png" # 指定服务器端接收的文件名 curl -X POST https://api.example.com/upload \ -F "file=@/path/to/local.txt;filename=uploaded.txt"

@ 符号告诉 cURL 读取文件内容而非当作普通字符串。如果误写成 -F "file=/path/to/file",服务器收到的是字面字符串而非文件内容,这是新手最常见的错误。

-T PUT 上传(原始文件流)

-T--upload-file 将文件作为请求体直接发送,默认使用 HTTP PUT 方法:

bash
# HTTP PUT 上传 curl -T /path/to/file.pdf https://api.example.com/files/document.pdf # FTP 上传 curl -T /path/to/file.zip ftp://ftp.example.com/upload/ \ --user username:password # SFTP 上传 curl -T /path/to/file.zip sftp://example.com/upload/ \ --user username:password

-T-F 的关键区别:-T 发送的是原始文件流,Content-Type 默认为 application/octet-stream,不会封装成 multipart 格式。RESTful API 中资源更新(如替换已有文件)常用这种方式。

多文件上传

bash
# 不同字段名上传多个文件 curl -X POST https://api.example.com/upload \ -F "avatar=@/path/to/avatar.jpg" \ -F "resume=@/path/to/resume.pdf" # 数组形式上传(后端用 files[] 接收) curl -X POST https://api.example.com/upload \ -F "files[]=@/path/to/file1.pdf" \ -F "files[]=@/path/to/file2.jpg" # 混合文件和普通表单字段 curl -X POST https://api.example.com/submit \ -F "name=张三" \ -F "email=zhangsan@example.com" \ -F "avatar=@/path/to/avatar.jpg"

二进制上传与 Base64 编码

直接发送原始二进制数据,适用于 API 要求 application/octet-stream 的场景:

bash
curl -X POST https://api.example.com/upload \ -H "Content-Type: application/octet-stream" \ --data-binary @/path/to/file.bin # 从标准输入读取 cat file.bin | curl -X POST https://api.example.com/upload \ -H "Content-Type: application/octet-stream" \ --data-binary @-

某些 API 只接受 JSON 请求体,此时需要 Base64 编码:

bash
curl -X POST https://api.example.com/upload \ -H "Content-Type: application/json" \ -d "{\"file\":\"$(base64 -w 0 /path/to/file.pdf)\",\"filename\":\"document.pdf\"}"

Base64 编码会使数据体积增加约 33%,大文件场景下应优先使用 -F 表单上传。

大文件上传与断点续传

bash
# 显示上传进度条 curl -X POST https://api.example.com/upload \ -F "file=@/path/to/large.zip" \ --progress-bar # 断点续传(需要服务器支持 Range 或 resumable upload) curl -C - -X POST https://api.example.com/upload \ -F "file=@/path/to/large.zip" # 设置超时避免长时间挂起 curl --max-time 600 -F "file=@large.zip" \ https://api.example.com/upload

-C - 表示自动从上次中断的位置继续传输。注意:真正的断点续传需要服务端支持,对于 multipart 上传,多数服务器并不支持续传,这时需要使用服务端提供的分块上传 API(先获取 uploadId,逐块上传后合并)。

带认证的上传

bash
# Bearer Token 认证 curl -X POST https://api.example.com/upload \ -H "Authorization: Bearer your_token" \ -F "file=@/path/to/file.pdf" # AWS S3 预签名 URL 上传(PUT 方式) curl -X PUT "https://presigned-url-here" \ -H "Content-Type: application/pdf" \ --data-binary @/path/to/file.pdf # 基本认证 curl -u username:password -F "file=@file.pdf" \ https://api.example.com/upload

关键参数速查

参数作用适用场景
-F / --formmultipart 表单上传Web 表单、API 文件字段
-T / --upload-filePUT 原始文件流上传RESTful 资源替换、FTP/SFTP
@读取文件内容-F--data-binary
;type=指定 MIME 类型-F 中覆盖自动检测
;filename=指定服务端文件名-F 中需要改名的场景
--data-binary发送原始二进制数据application/octet-stream
-C -断点续传大文件中断后恢复
--progress-bar显示进度条大文件上传监控

面试常见追问

-F 和 -T 上传有什么区别? -F 封装为 multipart/form-data 格式,可以同时传文件和其他字段,适合表单场景。-T 发送原始文件流作为请求体,默认 PUT 方法,适合直接替换资源或 FTP/SFTP 上传。

上传文件时 @ 符号的作用是什么? @ 告诉 cURL 读取后面路径的文件内容。不加 @ 时,cURL 会把路径字符串当作普通值发送。

如何上传超过服务器限制的大文件? 分两种情况:如果是服务器 Content-Length 限制,需服务端调整配置;如果是需要分块上传,要调用服务端提供的 chunked upload API,cURL 本身不自动分块。

标签:cURL