用TP5框架写了个上传多个文件的表单
HTML代码:
<html>
<head>
<title>title>
head>
<body>
<form action="{:url('uploads')}"enctype="multipart/form-data" method="post">
<input type="file" name="image[]" /> <br>
<input type="file" name="image[]" /> <br>
<input type="file" name="image[]" /> <br>
<input type="submit" value="上传" />
form>
body>
html>
PHP代码:
public function uploads(){
$files = request()->file('image');
foreach($files as $file){
$info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
if($info){
// 成功上传后 获取上传信息
// 输出 jpg
echo $info->getExtension();
// 输出 20160820/42a79759f284b767dfcb2a0197904287.jpg
echo $info->getSaveName();
// 输出 42a79759f284b767dfcb2a0197904287.jpg
echo $info->getFilename();
}else{
// 上传失败获取错误信息
echo $file->getError();
}
}
}
上传三个很简单的文本文件,通过Fiddler截取Http请求如下
POST http://localhost/index/index/uploads.html HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 515
Cache-Control: max-age=0
Origin: http://localhost
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarymCVtBW9oc2PEnvDj
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost/index/index/index
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8
Cookie: pgv_pvi=6689128448; Phpstorm-ba9458cf=5f1ce810-71dc-4a40-821d-4699b7059873; PHPSESSID=1aq8lag529a7ff75l096928g90
------WebKitFormBoundarymCVtBW9oc2PEnvDj
Content-Disposition: form-data; name="image[]"; filename="TestFile1.txt"
Content-Type: text/plain
test file 1
------WebKitFormBoundarymCVtBW9oc2PEnvDj
Content-Disposition: form-data; name="image[]"; filename="TestFile2.txt"
Content-Type: text/plain
test file 2
------WebKitFormBoundarymCVtBW9oc2PEnvDj
Content-Disposition: form-data; name="image[]"; filename="TestFile3.txt"
Content-Type: text/plain
test file 3
------WebKitFormBoundarymCVtBW9oc2PEnvDj--
和不上传文件的Http请求对比,能看到几个显著地不同:
//说明我的请求是提交一个表单,boundary用来区分同时上传的几个文件的标识
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarymCVtBW9oc2PEnvDj
除Http的Header以外在Http请求的Body中有对上传的三个文本文件的描述。
这些文件描述的整体格式是“–文件描述–”
对于每个文件描述来说都要用boundary定义的字符串来包裹住
每个文件描述包含的内容是:
Content-Disposition:对上传内容的描述
Content-Type:上传文件的类型
之后就是文件的数据,因为这个例子里上传的是文本类型的,所以在Fiddler中可以正确显示出来,如果是其他类型的文件比如图片或音视频,则显示在Fiddler中的是一大堆的乱码。
但是通过上面的展示我们就已经了解了使用网页上传文件时http的细节。
那么用OKHttp3上传文件是什么样的呢?
val url = "http://192.168.9.80/index/index/uploads"
/* 第一个要上传的file */
val file1 = File(getExternalStorageDirectory().getAbsolutePath() + "/TestFile1.txt")
val fileBody1 = RequestBody.create(MediaType.parse("text/plain"), file1)
val file1Name = "testFile1.txt"
/* 第二个要上传的文件*/
val file2 = File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/TestFile2.txt")
val fileBody2 = RequestBody.create(MediaType.parse("text/plain"), file2)
val file2Name = "testFile2.txt"
/* 第三个要上传的文件*/
val file3 = File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/TestFile3.txt")
val fileBody3 = RequestBody.create(MediaType.parse("text/plain"), file3)
val file3Name = "testFile3.txt"
/* form的分割线,自己定义 */
val boundary = "----yang--------------------------------------------------------------yang"
val mBody = MultipartBody.Builder(boundary).setType(MultipartBody.FORM)
/* 上传了三个文件 */
.addFormDataPart("image[]", file1Name, fileBody1)
.addFormDataPart("image[]", file2Name, fileBody2)
.addFormDataPart("image[]", file3Name, fileBody3)
.build()
val okHttpClient = OkHttpClient()
val request = Request.Builder()
.url(url)
.post(mBody)
.build()
val call = okHttpClient.newCall(request)
call.enqueue(object: Callback{
override fun onFailure(p0: Call?, p1: IOException?) {
}
override fun onResponse(p0: Call?, p1: Response?) {
}
})
对应的Http请求如下
POST http://192.168.9.80/index/index/uploads HTTP/1.1
Content-Type: multipart/form-data; boundary=----yang--------------------------------------------------------------yang
Content-Length: 719
Host: 192.168.9.80
Connection: Keep-Alive
Accept-Encoding: gzip
Cookie: PHPSESSID=3ignhso5d41h591f0nn4cduhf4
User-Agent: okhttp/3.8.1
------yang--------------------------------------------------------------yang
Content-Disposition: form-data; name="image[]"; filename="testFile1.txt"
Content-Type: text/plain
Content-Length: 11
test file 1
------yang--------------------------------------------------------------yang
Content-Disposition: form-data; name="image[]"; filename="testFile2.txt"
Content-Type: text/plain
Content-Length: 11
test file 2
------yang--------------------------------------------------------------yang
Content-Disposition: form-data; name="image[]"; filename="testFile3.txt"
Content-Type: text/plain
Content-Length: 11
test file 3
------yang--------------------------------------------------------------yang--
通过这样的对比分析,我们就能够知道在我们使用OKHttp3进行文件上传的时候,到底都是在做什么了,说白了,实际上就是去模仿浏览器中的操作,把那些原本由浏览器帮我们做好的事情,自己去框架的接口去实现而已。