Java中用Socket实现HTTP文件上传实例

时间:2022-09-21 21:17:56

我想做过web开发的程序员大部分都做过文件上传的功能,大多数时候我们都是借助于commons-fileupload这样的jar包实现的。下面我试着通过读取Socket的输入流来实现一个文件上传的功能。

在做文件上传之前我们需要先了解一下HTTP POST的附件上传协议。HTTP附件上传协议是RFC1876协议,RFC1876协议是在HTTP协议的基础上为INPUT标签增加了file属性,同时限定了Form的method必须为POSTENCTYPE必须为multipart/form-data。RFC1867协议对HTTP头作了适当地变更,content-type头由以前的:content-type:application/x-www-form-urlencoded变为content-type:multipart/form-data;+空格+boundary=字符串。RFC1867增加了文件上传得功能,而上传文件内容自然也会被加入到HTTP的实体中。现在因为既有HTTP一般的参数实体,又有上传文件的实体,所以用boundary把每种实体进行了分割。具体的看下图:

Java中用Socket实现HTTP文件上传实例

接下来就开始我们的代码部分吧。

我在前面的文章中写过创建一个自己的Web服务器,现在我们的重点要放在对socket的输入流的解析中。具体代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
public void parseRequest() {
  LineNumberReader br = new LineNumberReader(new InputStreamReader(inputStream));
  StringBuffer sb = new StringBuffer();
  String str = null;
  try {
    //读取请求行
    String requestLine = br.readLine();
    if (!StringUtils.isEmpty(requestLine)) {
      sb.append(requestLine);
      String[] reqs = requestLine.split(" ");
      if (reqs != null && reqs.length > 0) {
        if ("GET".equals(reqs[0])) {
          method = "GET";
        } else {
          method = "POST";
        }
      }
    }
    //读取请求头
    while ((str = br.readLine()) != null) {
      if ("".equals(str)) {
        break;
      }
      if (!StringUtils.isEmpty(str)) {
        if (str.indexOf(":") > 0) {
          String[] strs = str.split(":");
          headers.put(strs[0].toLowerCase(), strs[1].trim());
        }
      }
      sb.append(str).append("\n");
    }
    //POST请求,Content-type为 multipart/form-data
    String contentType = null;
    if ("POST".equals(method) && ((contentType = headers.get("content-type")) != null
        && headers.get("content-type").startsWith("multipart/form-data"))) {
      //文件上传的分割位 这里只处理单个文件的上传
      String boundary = contentType.substring(contentType.indexOf("boundary") +
          "boundary=".length());
      //解析消息体
      while ((str = br.readLine()) != null) {
        //解析结束的标记
        do {
          //读取boundary中的内容
          //读取Content-Disposition
          str = br.readLine();
          //说明是文件上传
          if (str.indexOf("Content-Disposition:") >= 0 && str.indexOf("filename") > 0) {
            str = str.substring("Content-Disposition:".length());
            String[] strs = str.split(";");
            String fileName = strs[strs.length - 1].replace("\"", "").split("=")[1];
            System.out.println("fileName = " + fileName);
            //这一行是Content-Type
            br.readLine();
            //这一行是换行
            br.readLine();
            //正式去读文件的内容
            BufferedWriter bw = null;
            try {
              bw = new BufferedWriter(new OutputStreamWriter(new
                  FileOutputStream("G:\\LearnVideo\\fileLoad" +
                  File.separator + fileName), "UTF-8"));
              while (true) {
                str = br.readLine();
                if (str.startsWith("--" + boundary)) {
                  break;
                }
                bw.write(str);
                bw.newLine();
              }
              bw.flush();
            } catch (Exception e) {
 
            } finally {
              if (bw != null) {
                bw.close();
              }
            }
          }
          if (str.indexOf("Content-Disposition:") >= 0) {
            str = str.substring("Content-Disposition:".length());
            String[] strs = str.split(";");
            String name = strs[strs.length - 1].replace("\"", "").split("=")[1];
            br.readLine();
            StringBuilder stringBuilder = new StringBuilder();
            while (true) {
              str = br.readLine();
              if (str.startsWith("--" + boundary)) {
                break;
              }
              stringBuilder.append(str);
            }
            parameters.put(name, stringBuilder.toString());
          }
        } while (("--" + boundary).equals(str));
        //解析结束
        if (str.equals("--" + boundary + "--")) {
          break;
        }
      }
    }
    //System.out.println(sb.toString());
    //获取URI
    uri = StringUtils.parserUri(sb.toString(), " ");
    int flag = -1;
    //说明有参数
    if ((flag = uri.indexOf('?')) >= 0) {
      String oldUri = uri;
      uri = uri.substring(0,flag);
      String parameterPath = oldUri.substring(flag+1);
      String[] parameter = parameterPath.split("&");
      if (parameter != null && parameter.length > 0) {
        for (int i = 0; i < parameter.length; i++) {
          String str1 = parameter[i];
          if((flag = str1.indexOf('=')) >= 0){
            String key = str1.substring(0,flag);
            String value = str1.substring(flag+1);
            parameters.put(key,value);
          }else{
            parameters.put(str,null);
          }
        }
      }
    }
  } catch (IOException e) {
    e.printStackTrace();
  }
}

我们启动自己创建的Web服务器,然后在浏览器中输入:http://localhost:8004/static/uploadPage.html,页面如下:

Java中用Socket实现HTTP文件上传实例

选择我们要上次的文件,然后点击上传按钮,我们会发现我们的功能已经被上传到G:\LearnVideo\fileLoad这个目录下了。示例如下:

Java中用Socket实现HTTP文件上传实例

完整的代码请从这里下载:FullStackTraining.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://blog.csdn.net/zknxx/article/details/60884573