用Socket实现HTTP文件上传

简介: 我想做过web开发的程序员大部分都做过文件上传的功能,大多数时候我们都是借助于commons-fileupload这样的jar包实现的。下面我试着通过读取Socket的输入流来实现一个文件上传的功能。 在做文件上传之前我们需要先了解一下HTTP POST的附件上传协议。HTTP附件上传协议是RFC1876协议,RFC1876协议是在HTTP协议的基础上为INPUT标签增加了file属性,

我想做过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把每种实体进行了分割。具体的看下图:


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

我在前面的文章中写过创建一个自己的Web服务器,我们在这篇文章中还是使用上次创建的服务器如果不知道这篇文章在哪里的话,请点击这里。现在我们的重点要放在对socket的输入流的解析中。具体代码如下:

    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,页面如下:

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


完整的代码请从这里下载:http://download.csdn.net/detail/zknxx/9774786









相关文章
|
安全 网络协议 网络安全
http https socket通讯详解?
http https socket通讯详解?
263 0
|
3月前
|
网络协议 API
区分TCP/IP、HTTP、Socket三者的差异
HTTP关注于应用层的协议规范,而Socket关注于为应用程序提供编程中的网络功能,这些功能本身是建立在底层的TCP/IP协议之上;HTTP是更高层次的抽象,定义了如何包装数据,而TCP/IP定义了如何传送数据,Socket则是两者之间在程序中的桥梁,负责实现细节。在实际应用中,通常HTTP通信也是通过Socket来完成,因为HTTP仅是具体内容的封装形式,而Socket则是传送方式的实现形式。
345 16
|
3月前
|
网络协议 安全 API
WebSocket、Socket、TCP 和 HTTP 的差别与应用场景
WebSocket、Socket、TCP 和 HTTP 是网络通信中的四大“使者”,各具特色:HTTP 适合短时请求,TCP 稳定可靠,Socket 灵活定制,WebSocket 实现实时双向通信。本文用通俗语言解析它们的区别与应用场景,助你为项目选择最合适的通信方式。
1276 3
|
开发框架 网络协议 Unix
【嵌入式软件工程师面经】Socket,TCP,HTTP之间的区别
【嵌入式软件工程师面经】Socket,TCP,HTTP之间的区别
508 1
|
11月前
|
安全 前端开发 JavaScript
利用HTTP协议进行文件上传和下载的常见方法
【10月更文挑战第25天】可以利用HTTP协议方便地实现文件的上传和下载功能,满足不同应用场景下的需求。在实际应用中,还可以根据具体的业务需求和安全要求,对文件上传和下载的过程进行进一步的优化和安全处理。
|
Linux Python
【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https
【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https
185 0
|
程序员 API 开发者
Socket与HTTP协议的实践
【6月更文挑战第4天】本文介绍了Python中的网络编程,包括Socket编程和基于HTTP协议的实践。Socket编程是网络通信的基础,Python的`socket`模块简化了其使用。文中展示了服务器和客户端的简单示例,以及如何通过多线程处理多个客户端连接。另外,文章讨论了HTTP协议,推荐了`requests`库,并给出了发送GET和POST请求的例子。最后,总结了Socket编程和HTTP协议在网络编程中的应用及其在Web开发和API交互中的重要性。
|
移动开发 Java
Java Socket编程 - 基于Socket实现HTTP下载客户端
Java Socket编程 - 基于Socket实现HTTP下载客户端
173 1
|
网络协议 网络安全 程序员
socket,tcp,http三者之间的原理和区别
socket,tcp,http三者之间的原理和区别
socket,tcp,http三者之间的原理和区别
|
网络协议 Linux Windows
TCP/IP、Http、Socket之间的区别
TCP/IP、Http、Socket之间的区别
486 3