用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









相关文章
|
6月前
|
安全 网络协议 网络安全
http https socket通讯详解?
http https socket通讯详解?
|
1天前
|
安全 网络安全 开发工具
对象存储oss使用问题之flutter使用http库进行post请求文件上传返回400如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
14 1
|
4月前
|
网络协议 应用服务中间件 Go
go语言中的socket和http
go语言中的socket和http
34 0
|
4月前
|
网络协议 API 开发者
百度搜索:蓝易云【Websocket、Socket、HTTP之间的关系。】
总结: HTTP是一种无状态协议,常用于传输静态资源;Socket是一种编程接口,用于实现网络通信;Websocket是在HTTP之上实现的全双工通信协议。它们在通信方式、连接状态和应用场景上存在区别,适用于不同的网络通信需求。
33 0
|
4月前
|
存储 API 分布式数据库
C/C++ 通过HTTP实现文件上传下载
WinInet(Windows Internet)是 Microsoft Windows 操作系统中的一个 API 集,用于提供对 Internet 相关功能的支持。它包括了一系列的函数,使得 Windows 应用程序能够进行网络通信、处理 HTTP 请求、FTP 操作等。WinInet 提供了一套完整的网络通信工具,使得开发者能够轻松地构建支持网络功能的应用程序,涵盖了从简单的 HTTP 请求到复杂的文件传输等多种网络操作。
89 1
C/C++ 通过HTTP实现文件上传下载
|
XML Java 数据格式
Java,InputStream,Socket阻塞.(关于HTTP请求的IO问题自我总结)
Java,InputStream,Socket阻塞.(关于HTTP请求的IO问题自我总结)
271 0
|
监控 网络协议 安全
socket和http是什么,socket和http对比
socket和http是什么,socket和http对比
184 0
|
开发框架 网络协议 Unix
socket,tcp,http三者之间的区别
socket,tcp,http三者之间的区别
109 0
|
网络协议 Java 应用服务中间件
使用Java Socket手撸一个http服务器
作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomcat的底层是怎么支持http服务的呢?大名鼎鼎的Servlet又是什么东西呢,该怎么使用呢? 在初学java时,socket编程是逃不掉的一章;虽然在实际业务项目中,使用这个的可能性基本为0,本篇博文将主要介绍如何使用socket来实现一个简单的http服务器功能,提供常见的get/post请求支持,并再此过程中了解下http协议
127 0
使用Java Socket手撸一个http服务器
|
监控 网络协议 程序员
TCP/IP、Http、Socket的区别
TCP/IP、Http、Socket的区别
122 0