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 的场景:
bashcurl -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 编码:
bashcurl -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 / --form | multipart 表单上传 | Web 表单、API 文件字段 |
-T / --upload-file | PUT 原始文件流上传 | 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 本身不自动分块。