如何解析HTTP POST上传文件请求报文 本帖最后由 wudeaaa 于 2010-11-11 16:11:51 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 看RFC文档吧:http://www.faqs.org/rfcs/rfc1867.html request.getInputStream()获取输入流,然后转成文件输入流,用read方法读取就可以了啊。 文档看过来,里面没有说怎么接收(可能是我没看到?),就是根据表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[],再写入文件中,但是文件格式错误、}} 这种是标准的上传文件格式啦,用smartupload或者commons-fileupload就可以解释了,根本不需要自己做 没必要手工处理,手工处理的话如果你不熟知 RFC 关于 HTTP 协议的规范,是做不出来的。处理文件上传的开源框架有很多,比如:Apache Commons 的 FileUpload、O'Reilly 的 COS 等等。 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,返回的是这段的字节数组。比较繁琐 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; } /** 获取反馈内容 */ responseXML = postMethod.getResponseBodyAsString(); InputStream is=postMethod.getResponseBodyAsStream(); byte[] out=postMethod.getResponseBody(); 其中根据自己需要保存反馈内容,哥好多年没来csdn了,今天忽然有兴趣,来逛逛,^_^。 java正则匹配 请教一个问题,请大侠们帮忙,谢谢 问个对字符串加密的问题。。。。在线等待....... Java语言博客群发软件开发 一道SCJP的题目 跪求xsl的解决方法,急,急,急............. ★★请高手讲解catch、finally、thows ioexecption的区别? java中有没有类似的MessageBox()函数 JBuilder和vj那个更好用,给个理由最好,谢谢 weblogic连接池的问题 c# 初学者菜鸟问题,javac的用法
http://www.faqs.org/rfcs/rfc1867.html
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[],再写入文件中,但是文件格式错误、
}
}
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,返回的是这段的字节数组。比较繁琐
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;
}
responseXML = postMethod.getResponseBodyAsString();
InputStream is=postMethod.getResponseBodyAsStream();
byte[] out=postMethod.getResponseBody();
其中根据自己需要保存反馈内容,哥好多年没来csdn了,今天忽然有兴趣,来逛逛,^_^。