使用 HTTPHandler 上传文件 [英] File Upload using HTTPHandler

查看:32
本文介绍了使用 HTTPHandler 上传文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 HTTPHandler 上传文件(多部分表单数据).

WebKit 边界正在写入目标文件,从而损坏文件.

输入文件可以是任何类型的文件,包括文本、zip、apk 等

代码:

 public void handle(HttpExchange httpExchange) 抛出 IOException {URI uri = httpExchange.getRequestURI();String httpReqMethod = httpExchange.getRequestMethod();标头标头 = httpExchange.getRequestHeaders();InputStream inputStrm = null;FileOutputStream destFile = null;String contentType = ((headers.get("Content-type") != null) ? (headers.get("Content-type").toString()) : (null));httpExchange.getRequestURI().getQuery());映射<字符串,字符串>queryParams = queryToMap(httpExchange.getRequestURI().getQuery());设置<字符串>键= headers.keySet();迭代器<字符串>itr = keys.iterator();而(itr.hasNext()){String key = (String)itr.next();}File file = new File(ACEConstants.WEB_SERVER_CTX_ROOT + uri.getPath()).getCanonicalFile();字符串资源 = uri.getPath().substring(uri.getPath().indexOf(ACEConstants.WEB_SERVER_CTX_ROOT)+ACEConstants.WEB_SERVER_CTX_ROOT.length()+1);if(httpReqMethod.equals(ACEConstants.HTTP_REQUEST_METHOD_POST)){if(contentType != null && contentType.contains("multipart/form-data")){if(resource.equals("fileUpload")){inputStrm = httpExchange.getRequestBody();destFile = new FileOutputStream(new File("D:\"+queryParams.get("fileName")));String contentLength = headers.get("Content-length").toString();long fileSize = (Long.parseLong(contentLength.substring(1, contentLength.length()-1)));整数迭代 = 1;long bytesToBeRead = (fileSize > 1024) ?((iteration * 1024)) : (inputStrm.available());long bytesRemaining = (fileSize) - (iteration * 1024);字节[]字节=新字节[1024];如果(文件大小 <= 1024){字节 = 新字节[inputStrm.available()];inputStrm.read(bytes);destFile.write(bytes);}别的 {while (inputStrm.read(bytes) != -1) {迭代++;destFile.write(bytes);bytesRemaining = ( fileSize - ((iteration-1) * 1024));如果(剩余字节数 >= 1024){bytesToBeRead = 1024;字节=新字节[1024];}别的 {字节 = 新字节[inputStrm.available()];inputStrm.read(bytes);destFile.write(bytes);休息;}}}destFile.close();}}}}

这是 HTML 代码

<head lang="en"><meta charset="UTF-8"><title></title><script type="text/javascript">函数 processForm(frm){var fu1 = document.getElementsByName("数据文件");var 文件名 = fu1[0].value;filename = filename.substring(filename.lastIndexOf("\")+1);alert("您选择了" + 文件名);frm.action = "http://localhost:64444/ACE/fileUpload?fileName="+filename;返回真;}<身体><form name="myForm" enctype="multipart/form-data" method="post" acceptcharset="UTF-8" onsubmit="processForm(this);"><p>请指定一个文件或一组文件:
<input type="file" name="datafile" size="40"></p><div><输入类型=提交"值=发送">

</表单>

这里出了什么问题?非常感谢您的帮助.

编辑 1:

如果输入文件是包含文本的文本文件:1234567890
输出文件有内容:

 ------WebKitFormBoundaryKBRUiUWrIpW9wq2j内容配置:表单数据;名称=文本行"------WebKitFormBoundaryKBRUiUWrIpW9wq2j内容配置:表单数据;名称=数据文件";文件名=测试.txt"内容类型:文本/纯文本1234567890------WebKitFormBoundaryKBRUiUWrIpW9wq2j--

解决方案

如何使用 HttpHandler 上传文件

文件上传到 HttpHandler 导致边界和其他 MIME 信息被写入请求内容.由于解析此信息非常复杂且容易出错,因此可以使用 Commons FileUpload 事实证明,这在经典的 Servlet 环境中非常有效.

考虑这个带有定制ContextRequest 的例子.这将处理由 multipart/form-data 添加到您的请求正文中的所有边界解析,同时仍然允许您保留 HttpHandler 接口.

主要思想包括实现自己版本的 ContextRequest 以处理 HttpHandler 中提供的数据:

 public HttpHandlerRequestContext 实现 RequestContext {私有 HttpExchange http;公共 HttpHandlerRequestContext(HttpExchange http) {this.http = http;}@覆盖公共字符串 getCharacterEncoding() {//需要弄清楚这一点返回UTF-8";}@覆盖公共 int getContentLength() {//经过测试可以使用 0 作为返回值.反正已弃用返回0;}@覆盖公共字符串 getContentType() {//Content-Type 包含解析所需的边界返回 http.getRequestHeaders().getFirst("Content-type");}@覆盖public InputStream getInputStream() 抛出 IOException {//传递输入流返回 http.getRequestBody();}}

供参考:这是一个列出接收到的文件的工作示例.

import java.io.IOException;导入 java.io.InputStream;导入 java.io.OutputStream;导入 java.net.InetSocketAddress;导入 java.util.List;导入 java.util.Map.Entry;导入 org.apache.commons.fileupload.FileItem;导入 org.apache.commons.fileupload.RequestContext;导入 org.apache.commons.fileupload.disk.DiskFileItemFactory;导入 org.apache.commons.fileupload.servlet.ServletFileUpload;导入 com.sun.net.httpserver.HttpExchange;导入 com.sun.net.httpserver.HttpHandler;导入 com.sun.net.httpserver.HttpServer;公共类 HttpServerTest {public static void main(String[] args) 抛出异常 {HttpServer 服务器 = HttpServer.create(new InetSocketAddress(8000), 0);server.createContext("/fileupload", new MyHandler());server.setExecutor(null);//创建一个默认执行器服务器开始();}静态类 MyHandler 实现了 HttpHandler {@覆盖公共无效句柄(最终 HttpExchange t)抛出 IOException {for(Entry> header : t.getRequestHeaders().entrySet()) {System.out.println(header.getKey() + ": " + header.getValue().get(0));}DiskFileItemFactory d = new DiskFileItemFactory();尝试 {ServletFileUpload up = new ServletFileUpload(d);列表<文件项>结果 = up.parseRequest(new RequestContext() {@覆盖公共字符串 getCharacterEncoding() {返回UTF-8";}@覆盖公共 int getContentLength() {返回0;//测试使用 0 作为返回值}@覆盖公共字符串 getContentType() {返回 t.getRequestHeaders().getFirst("Content-type");}@覆盖public InputStream getInputStream() 抛出 IOException {返回 t.getRequestBody();}});t.getResponseHeaders().add("Content-type", "text/plain");t.sendResponseHeaders(200, 0);OutputStream os = t.getResponseBody();for(FileItem fi : 结果) {os.write(fi.getName().getBytes());os.write("
".getBytes());System.out.println("文件项:" + fi.getFieldName() + " = " + fi.getName());}os.close();} 捕获(异常 e){e.printStackTrace();}}}}

I am trying to upload file (multi part form data) using HTTPHandler.

WebKit Boundary is getting written to the destination file, thus corrupting the file.

Input files can be any kind of files, including text, zip, apk etc.

Code:

    public void handle(HttpExchange httpExchange) throws IOException {

    URI uri = httpExchange.getRequestURI();
    String httpReqMethod = httpExchange.getRequestMethod();
    Headers headers = httpExchange.getRequestHeaders();
    InputStream  inputStrm = null;
    FileOutputStream destFile = null;
    String contentType = ((headers.get("Content-type") != null) ? (headers.get("Content-type").toString()) : (null));
    httpExchange.getRequestURI().getQuery());

    Map<String, String> queryParams = queryToMap(httpExchange.getRequestURI().getQuery());
    Set<String> keys= headers.keySet();
    Iterator<String> itr = keys.iterator();
    while(itr.hasNext())
    {
      String key = (String)itr.next();
    }

    File file = new File(ACEConstants.WEB_SERVER_CTX_ROOT + uri.getPath()).getCanonicalFile();
    String resource = uri.getPath().substring(
              uri.getPath().indexOf(ACEConstants.WEB_SERVER_CTX_ROOT)+ACEConstants.WEB_SERVER_CTX_ROOT.length()+1);

      if(httpReqMethod.equals(ACEConstants.HTTP_REQUEST_METHOD_POST) )
      {
        if(contentType != null && contentType.contains("multipart/form-data"))
        {
          if(resource.equals("fileUpload"))
          {
            inputStrm = httpExchange.getRequestBody();
            destFile = new FileOutputStream(new File("D:\"+queryParams.get("fileName")));
            String contentLength = headers.get("Content-length").toString();
            long fileSize = (Long.parseLong(contentLength.substring(1, contentLength.length()-1)));
            int iteration = 1;
            long bytesToBeRead = (fileSize > 1024) ? ((iteration * 1024)) : (inputStrm.available());
            long bytesRemaining = (fileSize) - (iteration * 1024);
              byte[] bytes = new byte[1024];

            if(fileSize <= 1024) 
            {
              bytes = new byte[inputStrm.available()];
              inputStrm.read(bytes);
              destFile.write(bytes);
            }
            else {

              while (inputStrm.read(bytes) != -1) {
                iteration++;
                destFile.write(bytes);
                bytesRemaining =  ( fileSize - ((iteration-1) * 1024));
                if (bytesRemaining >= 1024) {
                  bytesToBeRead = 1024;
                  bytes = new byte[1024];
                }
                else {
                  bytes = new byte[inputStrm.available()];

                  inputStrm.read(bytes);
                  destFile.write(bytes);
                  break;
                }
              }
            }
            destFile.close();
          }
        } 
      }
    }

Here's the HTML code

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">

        function processForm(frm)
        {
            var fu1 = document.getElementsByName("datafile");
            var filename = fu1[0].value;
            filename = filename.substring(filename.lastIndexOf("\")+1);
            alert("You selected " + filename);
            frm.action = "http://localhost:64444/ACE/fileUpload?fileName="+filename;
            return true;
        }

    </script>
</head>
<body>

<form name="myForm" enctype="multipart/form-data" method="post" acceptcharset="UTF-8" onsubmit="processForm(this);">
    <p>
        Please specify a file, or a set of files:<br>
        <input type="file" name="datafile" size="40">
    </p>
    <div>
        <input type="submit" value="Send">
    </div>
</form>

</body>
</html>

What is going wrong here? Help would be much appreciated.

EDIT 1:

If the input file is a text file containing text : 1234567890
The output file has contents :

 ------WebKitFormBoundaryKBRUiUWrIpW9wq2j
Content-Disposition: form-data; name="textline"


------WebKitFormBoundaryKBRUiUWrIpW9wq2j
Content-Disposition: form-data; name="datafile"; filename="test.txt"
Content-Type: text/plain

1234567890
------WebKitFormBoundaryKBRUiUWrIpW9wq2j--

解决方案

How to Upload Files with HttpHandler

File Upload to HttpHandler results in boundary and other MIME information being written into the request contents. As parsing this information is quite comples and error-prone, one could resort to use Commons FileUpload which is proven to work great in classic Servlet environments.

Consider this example with a custom made ContextRequest. This would handle all the parsing of boundaries added into your request body by multipart/form-data while still allowing you to keep HttpHandler interface.

The main idea consists of implementing an own version of ContextRequest to work with the data provided in HttpHandler:

   public HttpHandlerRequestContext implements RequestContext {

          private HttpExchange http;

          public HttpHandlerRequestContext(HttpExchange http) {
                this.http = http;
          }

          @Override
          public String getCharacterEncoding() {
                //Need to figure this out yet
                return "UTF-8"; 
          }

          @Override
          public int getContentLength() {
                //tested to work with 0 as return. Deprecated anyways
                return 0; 
          }

          @Override
          public String getContentType() {
                //Content-Type includes the boundary needed for parsing
                return http.getRequestHeaders().getFirst("Content-type");
          }

          @Override
          public InputStream getInputStream() throws IOException {
                 //pass on input stream
                return http.getRequestBody();
          }
 }

For reference: Here's a working example listing the received files.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map.Entry;

import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class HttpServerTest {

    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/fileupload", new MyHandler());
        server.setExecutor(null); // creates a default executor
        server.start();
    }

    static class MyHandler implements HttpHandler {
        @Override
        public void handle(final HttpExchange t) throws IOException {
            for(Entry<String, List<String>> header : t.getRequestHeaders().entrySet()) {
                System.out.println(header.getKey() + ": " + header.getValue().get(0));
            }
            DiskFileItemFactory d = new DiskFileItemFactory();      

            try {
                ServletFileUpload up = new ServletFileUpload(d);
                List<FileItem> result = up.parseRequest(new RequestContext() {

                    @Override
                    public String getCharacterEncoding() {
                        return "UTF-8";
                    }

                    @Override
                    public int getContentLength() {
                        return 0; //tested to work with 0 as return
                    }

                    @Override
                    public String getContentType() {
                        return t.getRequestHeaders().getFirst("Content-type");
                    }

                    @Override
                    public InputStream getInputStream() throws IOException {
                        return t.getRequestBody();
                    }

                });
                t.getResponseHeaders().add("Content-type", "text/plain");
                t.sendResponseHeaders(200, 0);
                OutputStream os = t.getResponseBody();               
                for(FileItem fi : result) {
                    os.write(fi.getName().getBytes());
                    os.write("
".getBytes());
                    System.out.println("File-Item: " + fi.getFieldName() + " = " + fi.getName());
                }
                os.close();

            } catch (Exception e) {
                e.printStackTrace();
            }            
        }
    }
}

这篇关于使用 HTTPHandler 上传文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆