如何解析HTTP POST上传文件请求报文

wudeaaa 2010-11-11 04:08:22
客户端HTTP POST上传文件报文如下,服务端需要获得文件流,然后写入文件(保持文件原来的格式),这个文件流如何解析获得?有什么好的方法吗?下面是上传一个pdf文件的信息。

POST /upload.jsp HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7da29f2d890386
Host: abc.com
Content-Length: 1516663
Connection: Keep-Alive
Cache-Control: no-cache

-----------------------------7da29f2d890386
Content-Disposition: form-data; name="ServerPath"

localhost
-----------------------------7da29f2d890386
Content-Disposition: form-data; name="id"

12323123
-----------------------------7da29f2d890386
Content-Disposition: form-data; name="FileData"; filename="D:\set.pdf"
Content-Type: application/pdf

%PDF-1.6
%����
1 0 obj<</Type/Page/Contents 2 0 R/Parent 3 0 R/Resources 4 0 R/CropBox[0 0 595.22 842]/MediaBox[0 0 595.22 842]/Rotate 0>>
endobj
4 0 obj<</ColorSpace<</Cs6 5 0 R>>/ExtGState<</GS1 6 0 R>>/ProcSet[/PDF/Text]/Font<</F1 7 0 R/F3 8 0 R/TT3 9 0 R/F2 10 0 R>>>>
endobj
2 0 obj <</Filter/FlateDecode/Length 1887>>stream
-----------------------------7da29f2d890386--

...全文
2741 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
没必要手工处理,手工处理的话如果你不熟知 RFC 关于 HTTP 协议的规范,是做不出来的。

处理文件上传的开源框架有很多,比如:Apache Commons 的 FileUpload、O'Reilly 的 COS 等等。
wudeaaa 2010-12-14
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 id19870510 的回复:]
哥们 你问题解决了没?

我也正在搞这个问题 ,
[/Quote]我用分段上传的,每接收一段后,就与已接收的合并,以追加的形式写入文件,当完成接收最后一段时完成接收。
-droidcoffee- 2010-12-14
  • 打赏
  • 举报
回复
哥们 你问题解决了没?

我也正在搞这个问题 ,
sandsworlf 2010-12-14
  • 打赏
  • 举报
回复
/** 获取反馈内容 */
responseXML = postMethod.getResponseBodyAsString();
InputStream is=postMethod.getResponseBodyAsStream();
byte[] out=postMethod.getResponseBody();

其中根据自己需要保存反馈内容,哥好多年没来csdn了,今天忽然有兴趣,来逛逛,^_^。
sandsworlf 2010-12-14
  • 打赏
  • 举报
回复
public String getResponseXml(String url) {
String responseXML = null;
try {
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpClient httpClient = new HttpClient(connectionManager);
log.debug("请求地址:" + url());
PostMethod postMethod = new PostMethod(url);
/** *将内容放入postMethod中** */
postMethod.setRequestBody("请求内容放入到该位置");

log.debug("开始接收业务处理反馈报文.\n");
/** *执行postMethod,并获取状态码 */
int statusCode = httpClient.executeMethod(postMethod);
log.debug("http返回码: "+statusCode);

if (statusCode != 200) {// 判断是否调用成功
log.error("调用失败,请确认地址是否正确");
}
/** 获取反馈内容 */
responseXML = postMethod.getResponseBodyAsString();

log.debug("反馈报文为:\n" + responseXML + "\n");
/** 连接释放 */
postMethod.releaseConnection();
} catch (HttpException e) {
log.error("HttpException异常,正在重试...");
e.printStackTrace();
} catch (IOException e) {
log.error("IOException异常,正在重试...\n");
e.printStackTrace();
}
return responseXML;
}
-droidcoffee- 2010-12-14
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 wudeaaa 的回复:]
引用 12 楼 id19870510 的回复:
引用 9 楼 wudeaaa 的回复:
引用 8 楼 id19870510 的回复:
哥们 你问题解决了没?

我也正在搞这个问题 ,
我用分段上传的,每接收一段后,就与已接收的合并,以追加的形式写入文件,当完成接收最后一段时完成接收。


可否把实现方式分享一下?


Java code

private byte[] ……
[/Quote]


谢了 哥们, 我研究一番。。。
wudeaaa 2010-12-14
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 id19870510 的回复:]
引用 9 楼 wudeaaa 的回复:
引用 8 楼 id19870510 的回复:
哥们 你问题解决了没?

我也正在搞这个问题 ,
我用分段上传的,每接收一段后,就与已接收的合并,以追加的形式写入文件,当完成接收最后一段时完成接收。


可否把实现方式分享一下?
[/Quote]

private byte[] parse(HttpServletRequest request) throws IOException {

final int NONE = 0;
final int DATAHEADER = 1;
final int FILEDATA = 2;
final int FIELDDATA = 3;

final int MXA_SEGSIZE = 1000 * 1024 * 10;//每批最大的数据量 10M

String contentType = request.getContentType();// 请求消息类型
String fieldname = ""; // 表单域的名称
String fieldvalue = ""; // 表单域的值
String filename = ""; // 文件名
String boundary = ""; // 分界符
String lastboundary = ""; // 结束符
String filePath = "";
Hashtable<String, String> formfields = new Hashtable<String, String>();
int filesize = 0; // 文件长度

int pos = contentType.indexOf("boundary=");

if (pos != -1) { // 取得分界符和结束符
pos += "boundary=".length();
boundary = "--" + contentType.substring(pos);
lastboundary = boundary + "--";
}
int state = NONE;
// 得到数据输入流reqbuf
DataInputStream in = new DataInputStream(request.getInputStream());
// 将请求消息的实体送到b变量中
int totalBytes = request.getContentLength();
String message = "";
if (totalBytes > MXA_SEGSIZE) {//每批大于10m时
message = "Each batch of data can not be larger than " + MXA_SEGSIZE / (1000 * 1024)
+ "M";
return null;
}
byte[] b = new byte[totalBytes];
in.readFully(b);
in.close();
String reqContent = new String(b, "UTF-8");//
BufferedReader reqbuf = new BufferedReader(new StringReader(reqContent));

boolean flag = true;
int i = 0;
while (flag == true) {
String s = reqbuf.readLine();
if ((s == null) || (s.equals(lastboundary)))
break;

switch (state) {
case NONE:
if (s.startsWith(boundary)) {
state = DATAHEADER;
i += 1;
}
break;
case DATAHEADER:
pos = s.indexOf("filename=");
if (pos == -1) { // 将表单域的名字解析出来
pos = s.indexOf("name=");
pos += "name=".length() + 1;
s = s.substring(pos);
int l = s.length();
s = s.substring(0, l - 1);
fieldname = s;
state = FIELDDATA;
} else { // 将文件名解析出来
String temp = s;
pos = s.indexOf("filename=");
pos += "filename=".length() + 1;
s = s.substring(pos);
int l = s.length();
s = s.substring(0, l - 1);// 去掉最后那个引号”
filePath = s;
pos = s.lastIndexOf("\\");
s = s.substring(pos + 1);
filename = s;
// 从字节数组中取出文件数组
pos = byteIndexOf(b, temp, 0);
b = subBytes(b, pos + temp.getBytes().length + 2, b.length);// 去掉前面的部分
int n = 0;
/**
* 过滤boundary下形如 Content-Disposition: form-data; name="bin";
* filename="12.pdf" Content-Type: application/octet-stream
* Content-Transfer-Encoding: binary 的字符串
*/
while ((s = reqbuf.readLine()) != null) {
if (n == 1)
break;
if (s.equals(""))
n++;

b = subBytes(b, s.getBytes().length + 2, b.length);
}
pos = byteIndexOf(b, boundary, 0);
if (pos != -1)
b = subBytes(b, 0, pos - 1);

filesize = b.length - 1;
formfields.put("filesize", String.valueOf(filesize));
state = FILEDATA;
}
break;
case FIELDDATA:
s = reqbuf.readLine();
fieldvalue = s;
formfields.put(fieldname, fieldvalue);
state = NONE;
break;
case FILEDATA:
while ((!s.startsWith(boundary)) && (!s.startsWith(lastboundary))) {
s = reqbuf.readLine();
if (s.startsWith(boundary)) {
state = DATAHEADER;
break;
}
}
break;
}
}
return b;

}

// 字节数组中的INDEXOF函数,与STRING类中的INDEXOF类似
public static int byteIndexOf(byte[] b, String s, int start) {
return byteIndexOf(b, s.getBytes(), start);
}

// 字节数组中的INDEXOF函数,与STRING类中的INDEXOF类似
public static int byteIndexOf(byte[] b, byte[] s, int start) {
int i;
if (s.length == 0) {
return 0;
}
int max = b.length - s.length;
if (max < 0)
return -1;
if (start > max)
return -1;
if (start < 0)
start = 0;
search: for (i = start; i <= max; i++) {
if (b[i] == s[0]) {
int k = 1;
while (k < s.length) {
if (b[k + i] != s[k]) {
continue search;
}
k++;
}
return i;
}
}
return -1;
}

// 用于从一个字节数组中提取一个字节数组
public static byte[] subBytes(byte[] b, int from, int end) {
byte[] result = new byte[end - from];
System.arraycopy(b, from, result, 0, end - from);
return result;
}

// 用于从一个字节数组中提取一个字符串
public static String subBytesString(byte[] b, int from, int end) {
return new String(subBytes(b, from, end));
}

主要实现是parse,返回的是这段的字节数组。比较繁琐
-droidcoffee- 2010-12-14
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 wudeaaa 的回复:]
引用 8 楼 id19870510 的回复:
哥们 你问题解决了没?

我也正在搞这个问题 ,
我用分段上传的,每接收一段后,就与已接收的合并,以追加的形式写入文件,当完成接收最后一段时完成接收。
[/Quote]

可否把实现方式分享一下?
ChDw 2010-11-12
  • 打赏
  • 举报
回复
这两个就是用来解析从IE上传的文件用的。它们都支持将上传的文件保存到你指定的位置
君望永远 2010-11-12
  • 打赏
  • 举报
回复
用组建啊~~
wudeaaa 2010-11-12
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 chdw 的回复:]
这种是标准的上传文件格式啦,用smartupload或者commons-fileupload就可以解释了,根本不需要自己做
[/Quote]这两个都是实现文件上传的?我想问的是怎么解析并保存上传的文件
ChDw 2010-11-11
  • 打赏
  • 举报
回复
这种是标准的上传文件格式啦,用smartupload或者commons-fileupload就可以解释了,根本不需要自己做
wudeaaa 2010-11-11
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 houjin_cn 的回复:]
看RFC文档吧:
http://www.faqs.org/rfcs/rfc1867.html
[/Quote]文档看过来,里面没有说怎么接收(可能是我没看到?),就是根据表rfc1867的规范上传的,服务端接收时,怎么解析得到文件流,我的方法是首先找到分隔符boundary,然后每次读1024个字节,
byte[] srcb = new byte[1024];
String content = "";
while(in.read(srcb) != -1){
for (int i = 0, j = 0; i < srcb.length - 1 && j <= i; i++) {
if (srcb[i] == 13 && srcb[i + 1] == 10) {//表示\r\n的ascii码,说明是一行
byte []sub = subBytes(srcb, j, i);//每一行(从j到i)字节数组
String line = new String(sub,"UTF-8");
//分析
...
if(line是正文)
content += line;()
}
然后把content转为byte[],再写入文件中,但是文件格式错误、
}
}
lunbing 2010-11-11
  • 打赏
  • 举报
回复
request.getInputStream()获取输入流,然后转成文件输入流,用read方法读取就可以了啊。
houjin_cn 2010-11-11
  • 打赏
  • 举报
回复

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧