如何使用multipartform-data格式上传文件
在网络编程过程中需要向服务器上传文件。Multipart/form-data是上传文件的一种方式。
Multipart/form-data其实就是浏览器用表单上传文件的方式。最常见的情境是:在写邮件时,向邮件后添加附件,附件通常使用表单添加,也就是用multipart/form-data格式上传到服务器。
表单形式上传附件
具体的步骤是怎样的呢?
首先,客户端和服务器建立连接(TCP协议)。
第二,客户端可以向服务器端发送数据。因为上传文件实质上也是向服务器端发送请求。
第三,客户端按照符合“multipart/form-data”的格式向服务器端发送数据。
既然Multipart/form-data格式就是浏览器用表单提交数据的格式,我们就来看看文件经过浏览器编码后是什么样子。
点击“Browse…”分别选择“unknowgif”和“unknow1gif”文件,点击“submit”按纽后,文件将被上传到服务器。
下面是服务器收到的数据:
服务器收到的数据
这是一个POST请求。所以数据是放在请求体内,而不是请求头内。
这行指出这个请求是“multipart/form-data”格式的,且“boundary”是 “---------------------------7db15a14291cce”这个字符串。
不难想象,“boundary”是用来隔开表单中不同部分数据的。例子中的表单就有 2 部分数据,用“boundary”隔开。“boundary”一般由系统随机产生,但也可以简单的用“-------------”来代替。
实际上,每部分数据的开头都是由"--" + boundary开始,而不是由 boundary 开始。仔细看才能发现下面的开头这段字符串实际上要比 boundary 多了个 “--”
紧接着 boundary 的是该部分数据的描述。
接下来才是数据。
“GIF”gif格式的文件头,可见,unknow1gif确实是gif格式。
在请求的最后,则是 "--" + boundary + "--" 表明表单的结束。
需要注意的是,在html协议中,用 “\r\n” 换行,而不是 “\n”。
下面的代码片断演示如何构造multipart/form-data格式数据,并上传到服务器。
//---------------------------------------
// this is the demo code of using multipart/form-data to upload text and photos
// -use WinInet APIs
//
//
// connection handlers
//
HRESULT hr;
HINTERNET m_hOpen;
HINTERNET m_hConnect;
HINTERNET m_hRequest;
//
// make connection
//
//
// form the content
//
std::wstring strBoundary = std::wstring(L"------------------");
std::wstring wstrHeader(L"Content-Type: multipart/form-data, boundary=");
wstrHeader += strBoundary;
HttpAddRequestHeaders(m_hRequest, wstrHeaderc_str(), DWORD(wstrHeadersize()), HTTP_ADDREQ_FLAG_ADD);
//
// "std::wstring strPhotoPath" is the name of photo to upload
//
//
// uploaded photo form-part begin
//
std::wstring strMultipartFirst(L"--");
strMultipartFirst += strBoundary;
strMultipartFirst += L"\r\nContent-Disposition: form-data; name=\"pic\"; filename=";
strMultipartFirst += L"\"" + strPhotoPath + L"\"";
strMultipartFirst += L"\r\nContent-Type: image/jpeg\r\n\r\n";
//
// "std::wstring strTextContent" is the text to uploaded
//
//
// uploaded text form-part begin
//
std::wstring strMultipartInter(L"\r\n--");
strMultipartInter += strBoundary;
strMultipartInter += L"\r\nContent-Disposition: form-data; name=\"status\"\r\n\r\n";
std::wstring wstrPostDataUrlEncode(CEncodeTool::Encode_Url(strTextContent));
// add text content to send
strMultipartInter += wstrPostDataUrlEncode;
std::wstring strMultipartEnd(L"\r\n--");
strMultipartEnd += strBoundary;
strMultipartEnd += L"--\r\n";
//
// open photo file
//
// ws2s(std::wstring)
// -transform "strPhotopath" from unicode to ansi
std::ifstream pstdofsPicInput = new std::ifstream;
pstdofsPicInput->open((ws2s(strPhotoPath))c_str(), std::ios::binary|std::ios::in);
pstdofsPicInput->seekg(0, std::ios::end);
int nFileSize = pstdofsPicInput->tellg();
if(nPicFileLen == 0)
{
return E_ACCESSDENIED;
}
char pchPicFileBuf = NULL;
try
{
pchPicFileBuf = new char[nPicFileLen];
}
catch(std::bad_alloc)
{
hr = E_FAIL;
}
if(FAILED(hr))
{
return hr;
}
pstdofsPicInput->seekg(0, std::ios::beg);
pstdofsPicInput->read(pchPicFileBuf, nPicFileLen);
if(pstdofsPicInput->bad())
{
pstdofsPicInput->close();
hr = E_FAIL;
}
delete pstdofsPicInput;
if(FAILED(hr))
{
return hr;
}
// Calculate the length of data to send
std::string straMultipartFirst = CEncodeTool::ws2s(strMultipartFirst);
std::string straMultipartInter = CEncodeTool::ws2s(strMultipartInter);
std::string straMultipartEnd = CEncodeTool::ws2s(strMultipartEnd);
int cSendBufLen = straMultipartFirstsize() + nPicFileLen + straMultipartIntersize() + straMultipartEndsize();
// Allocate the buffer to temporary store the data to send
PCHAR pchSendBuf = new CHAR[cSendBufLen];
memcpy(pchSendBuf, straMultipartFirstc_str(), straMultipartFirstsize());
memcpy(pchSendBuf + straMultipartFirstsize(), (const char )pchPicFileBuf, nPicFileLen);
memcpy(pchSendBuf + straMultipartFirstsize() + nPicFileLen, straMultipartInterc_str(), straMultipartIntersize());
memcpy(pchSendBuf + straMultipartFirstsize() + nPicFileLen + straMultipartIntersize(), straMultipartEndc_str(), straMultipartEndsize());
//
// send the request data
//
HttpSendRequest(m_hRequest, NULL, 0, (LPVOID)pchSendBuf, cSendBufLen)
可以通过iCloud功能恢复,具体步骤如下:
1、在 iPhone 的设置列表里,有 iCloud 服务功能选项,如图所示。
2、在 iCloud 功能列表里,有一项为“照片”选项,如图所示。
3、接下来如果我们之前打开了“我的照片流”这个选项的话,只要平时我们的手机接入无线网线时,它便会自动将手机上的照片上传到 iCloud 的照片流里。这就是在 iPhone 手机丢失以后,找回来的关键。如果你的 iPhone 上的照片比较重要的话,建议打开此选项。
4、在知道了找回照片的必要条件以后,接下来我们可以通过网页版的 iCloud 来找回照片。在电脑上打开 iCloud 官网,登录自己的 Apple ID 账户,如图所示。
5、接着在页面中,点击打开“照片”图标,如图所示。
6、由于当前 iCloud 网页版的“照片”为Beta版,可能载入的速度有一点慢。当出来以后,就可以在网页上把以前的照片下载到电脑上了。
7、如果在 iCloud 网页中,实在是打不开照片的话,我们还可以借用其它的 iOS 设备,如 iPhone、iPad 或 iPod Touch。在另外一部设备上用我们自己的 Apple ID 来登录 iCloud 服务,并打开“我的照片流”选项。
8、当成功登录以后,请将设备与无线连接起来,然后就请耐心等待系统把之前丢失手机中哪些照片流的照片同步回来就好了。
2 苹果手机拍的照片看不到怎么回事
你好,你如果是指在苹果手机的相册里面看不到的话,那是系统存储出了问题,只需要将手机重新安装系统既可以解决。
iphone导出相册的根本不需要用第三方工具比如iTunes或者iTools,手机连接到电脑后,在我的电脑里的“Apple iPhone便携式设备”这个文件夹下就有我们的相册和。可是为什么我的打开显示为空呢,这里我给大家说下原因和方法。
1连接手机后,我的电脑出现了“Apple iPhone便携式设备”这个文件夹,但是进去后,能显示有好多G的照片,可是进去后就是看不到,好懊恼!
2原来这是因为我们连接IPhone的时候,手机是锁定的,苹果为了避免手机隐私的泄露,是在锁屏的情况下是休想看到任何信息的。
3这里必须拔掉USB,把手机解锁后,重新连上电脑(这里注意一定要拔下来在解锁,连接状态解锁刷新是没有用的)。
4再次进入刚才那个文件夹,你会发现照片乖乖的躺在里面等待你处理。
3 苹果手机里的照片为什么会突然消失
苹果手机为什么照片突然都被清空?iPhone 照片突然消失怎么办?很多用户遇到这样的情况会非常紧张,以为自己照片全部丢失,其实无需慌张,只要不是用户的主观操作,iPhone 很少会出现丢失数据情况发生,大多数情况下数据都安全地储存在 iCloud 云端,只需要简单操作即可同步恢复到设备中。
为什么 iPhone 突然间照片全部消失?
如果设备没有进行过扩容等修改硬件的操作,基本可以排除硬件损坏导致数据丢失。
导致此故障的原因很可能是因为连接电脑 iTunes 时无意中同步照片,或者退出关闭 iCloud Photo 功能时,选择不保留云端数据,导致一次性清空了全部。
解决方法
● 前往iCloud 网页版查看照片是否仍存在,如果可以查看,则在 iPhone 设备上前往「设置」-「照片」,开启「iCloud 照片」与「上传到的照片流」将照片同步至设备。同步过程中可能将消耗大量网络数据,请尽量在稳定安全的 Wi-Fi 网络下进行数据同步,及注意保护 Apple ID 账户的安全。
● 前往「照片」,轻触底部的「相簿」标签页,下划查找并轻触「最近删除」,即可查看最近删除的项目,选择需要恢复的项目轻触「恢复」即可。
4 苹果手机相册中有些照片不显示是怎么回事
1、在电脑上面查看iPhone手机里面的照片,需要在连接时候点击确认信任电脑设备才可以。
2、使用手机数据线连接电脑跟iPhone手机,然后再手机屏幕上点击确认信任。
3、然后就可以在电脑——我的电脑——便携设备里面找到iPhone手机的照片,可以把照片复制出来,但是不可以往里面复制照片。
IPhone是苹果公司旗下研发的智能手机系列[1],它搭载苹果公司研发的iOS手机操作系统。第一代iPhone于2007年1月9日公司CEO史蒂夫·乔布斯发布,并在同年6月29日正式发售。
2013年9月10日,苹果公司推出第七代产品iPhone5C及iPhone5S,iPhone5S于同年9月20日正式发售。第八代的iPhone 6和iPhone6 Plus于2014年9月10日正式发布。2016年9月8日,iPhone 7和iPhone 7 Plus正式登台亮相,9月9日开启预约,9月16日正式开卖。2017年9月13日,苹果公司发布三款全新iPhone,47英寸的iPhone 8、55英寸的iPhone 8 Plus和58英寸的iPhone X。
5 为什么苹果手机的照片显示不出来
苹果手机照片显示不出来的一般原因是被系统隐藏了。
如下是解决办法:
一、连接
1、首先保证手机和电脑能够连接上,保证电脑能够读取手机的存储。
2、方法:有时候手机需要借助手机助手才能连接上,另外注意打开u 连接开关。
二、查找
1、一般电脑在读取手机设备后,可以对手机存储打开进行查找。
2、一般手机照片或者截频是放在DIMC这个文件夹中,下面的子文件夹是Camera照片就放在里面。
三、搜索功能
1、电脑搜索功能:
将手机照片的文件夹在搜索框中进行搜索查找照片。
2、winxp系统可以按快捷键Ctrl+F,然后搜索文件夹设置一些关键字查找更快。
四、直接借助QQ等设备
利用将发送到电脑QQ也是可以导入到电脑的。
6 苹果手机里面的照片不见了怎么办
iPhone手机中的照片不见是由于系统自动优化储存空间导致将照片上传备份到服务器,所以本地照片消失。
1、将 iPhone手机解锁至手机桌面下,在应用程序中找到设置图标打开。
2、进入手机系统的设置列表下,找到位于顶部的Apple ID。选项。
3、进入Apple ID的个人账号页面下后,选择icloud设置。
4、在icloud的应用程序列表中,找到照片设置打开。
5、将选项设置更改为下载并保留原件。(更改设置后,系统将会把已上传至服务器的照片原件下载回手机相册中)
6、成功更改设置后,按下HOME键返回至手机主屏幕页面下找到照片功能打开。
7、进入应用程序照片的主页面下,选择任意相册打开。
8、进入相册的管理页面下,即可恢复iPhone手机之前消失的照片。
相信很多开发者会把存放到七牛上,我的web站点也是吧存储到七牛上,对于以为主的站点,这样可以节省很大带宽。
将上传到七牛服务器的重点就是获得上传凭证uploadToken,直接把AccessKey和Secret放到客户端太不安全,容易被反编译。所以需要在服务器端根据AccessKey和Secret动态生成一个uploadToken,然后传回到客户端,客户端通过这个uploadToken将上传到七牛服务器。
第一、在服务器端生成uploadToken
//将上传到七牛 start
$bucket='七牛空间名称';
$expires = 3600;
$accessKey='去七牛查看';
$secretKey='去七牛查看';
$client = new QiniuClient($accessKey,$secretKey);
$flags = array();
$scope = $bucket;
$deadline = time() + $expires;
$flags['scope'] = $scope;
$flags['deadline'] = $deadline;
$flags['returnBody'] = null;
echo $client->uploadToken($flags);
这里注意一下bucket:七牛空间名称和deadline:uploadToken失效时间,具体可查看一下官网上传凭证介绍
uploadToken($flags)是自己封装的用于生成上传凭证的函数
public function uploadToken($flags) { if(!isset($flags['deadline'])) $flags['deadline'] = 3600 + time(); $encodedFlags = self::urlsafe_base64_encode(json_encode($flags)); $sign = hash_hmac('sha1', $encodedFlags, $this->secretKey, true); $encodedSign = self::urlsafe_base64_encode($sign); $token = $this->accessKey':'$encodedSign ':' $encodedFlags; return $token; }
public static function urlsafe_base64_encode($str){
$find = array("+","/");
$replace = array("-", "_");
return str_replace($find, $replace, base64_encode($str));
}
第二、下载qiniu-android-sdk-700jar和android-async-http-146并导入项目
第三、android上传
由于Android40 以后不允许在主线程进行网络连接,所以需要新开个线程来获取上传凭证。
/
上传到七牛
/
private void uploadImg(){
new Thread(new Runnable(){
@Override
public void run() {
//获得七牛上传凭证uploadToken
String token=getUploadToken();
//手机SD卡存放路径
String imgPath="";
try {
imgPath=FileUtilgetBasePath()+ "/testjpg";
} catch (IOException e) {
eprintStackTrace();
}
if(token!=null){
String data = imgPath;
//名称为当前日期+随机数生成
String key = getRandomFileName();
UploadManager uploadManager = new UploadManager();
uploadManagerput(data, key, token,
new UpCompletionHandler() {
@Override
public void complete(String arg0, ResponseInfo info, JSONObject response) {
// TODO Auto-generated method stub
Logi("qiniu", infotoString());
}
}, null);
}
else{
Logi("fail", "上传失败");
}
}
})start();
}
FileUtilgetBasePath()使用来获取SD卡基本路径,getRandomFileName()生成一个随机数来命名上传,具体方法我在这就不写了。
获得上传凭证的方法也很简单,直接使用httpget和服务器通信,获得第一步中生成的数据即可。(注意10022是模拟器提供的特殊IP,等同于在电脑端的环回测试IP127001)
/
获得七牛上传凭证uploadtoken
/
private String getUploadToken()
{
HttpClient client = new DefaultHttpClient();
StringBuilder builder = new StringBuilder();
HttpGet myget = new HttpGet("");
try {
HttpResponse response = clientexecute(myget);
BufferedReader reader = new BufferedReader(new InputStreamReader(
responsegetEntity()getContent()));
for (String s = readerreadLine(); s != null; s = readerreadLine()) {
builderappend(s);
}
return buildertoString();
} catch (Exception e) {
Logi("url response", "false");
eprintStackTrace();
return null;
}
}
通过LOG日志可以看到Qiniu--success,说明上传成功。
0条评论