Java使用HttpURLConnection构建multipart/form-data请求提交文件

2,375 阅读2分钟

报文格式几个要点说明


multipart/form-data请求主要用来提交媒体内容,也就是提交文件到服务端。multipart表示可以一次提交多个文件,每个文件在报文体中的一段。那么每段的开始结束就要有个约定来标识。body段分为body段头和段体两部分。 约定如下
每段约定格式
\r\n
--i-am-boundary \r\n                                  //说明这是段开始标识
Content-Disposition:name=file1;filename=aa.txt \r\n        //说明 这是段头
Content-Type: plain/text \r\n                             //说明 这是段头
\r\n                                                     //段头段体中空行
我是form表单提交的name=file1文件名为aa.txt的文件内容 \r\n     //这是段体
--i-am-boundary \r\n
Content-Disposition:name=file2;filename=bb.txt \r\n
Content-Type: plain/text \r\n
\r\n
我是form表单提交的name=file2文件名为vv.txt的文件内容 \r\n
--i-am-boundary-- \r\n

为了编码说明我用【\r\n】表示这是一个换行

  • 报文头headers Content-Type设置成如下
Content-Type:multipart/form-data;boundary=i-am-boundary

i-am-boundary为分割线,分割报文body的内容用的,boundary值可以随机生成比如用uuid,

  • 报文body段说明 【--i-am-boundary】为每段开始标识,前边加--
    【--i-am-boundary--】为报文body结束标识,前后加--
    【Content-Disposition,Content-Type】为body段的头部说明, 段头与段体之间留一个空行

代码如下

//--定义几个参数
private  static int  connectTimeout=1000*60*10;  //超时时间
private  static int  readTimeout=1000*60*10;
private static final String BOUNDARY = "SDIKitFormBoundary"
        +UUID.randomUUID().toString().replaceAll("-","").substring(0,16) ;  //定义BOUNDARY
private static final String PRE_FIX = ("\r\n--" + BOUNDARY + "\r\n"); //定义开始
private static final String END_FIX = ("\r\n--" + BOUNDARY + "--\r\n");  //定义结束

//--此为发送文件方法
public static   String postFile(String urlStr, String accept, byte[] fileContent, String fileFormName, String fileName, HashMap<String,String> postParam, HashMap<String,String> headersParam){

    HttpURLConnection con = null;
    DataOutputStream  outputStream=null;
    //  BufferedReader buffer = null;
    //StringBuffer resultBuffer = null;
    try {
        URL url = new URL(urlStr);
        //得到连接对象
        con = (HttpURLConnection) url.openConnection();
        con.setConnectTimeout(connectTimeout);
        con.setReadTimeout(readTimeout);
        con.setRequestMethod("POST");
        //设置请求需要返回的数据类型和字符集类型
        con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
        con.setRequestProperty("connection", "keep-alive");
        con.setRequestProperty("Accept",accept);
        //允许写出
        con.setDoOutput(true);
        //允许读入
        con.setDoInput(true);
        //不使用缓存
        con.setUseCaches(false);

        //----构建headers
        if(headersParam!=null&&!headersParam.keySet().isEmpty()){

            for(String key : headersParam.keySet()){
                con.setRequestProperty(key, headersParam.getOrDefault(key,""));
            }
        }

        //----构建file数据
          outputStream = new DataOutputStream(con.getOutputStream());
        // 要上传的数据
        StringBuffer strBuf = new StringBuffer();
        // 标识payLoad + 文件流的起始位置
        strBuf.append(PRE_FIX);
        strBuf.append("Content-Disposition: form-data; name=""+fileFormName+""; filename="" + fileName+ ""\r\n");
        strBuf.append("Content-Type: application/octet-stream" + "\r\n");
        strBuf.append("\r\n"); //留一个空行
        outputStream.write(strBuf.toString().getBytes());
        outputStream.write(fileContent);

        //二构建其他参数
        if(postParam!=null&&!postParam.keySet().isEmpty()){
            StringBuilder contentBody = new StringBuilder();
            for(String key : postParam.keySet()){
                contentBody.append(PRE_FIX);
                contentBody.append("Content-Disposition: form-data; name=""+key+""\r\n");
                contentBody.append("\r\n"); //参数换行
                contentBody.append(postParam.getOrDefault(key,"")); //参数值
            }
            outputStream.write(contentBody.toString().getBytes());
        }

        //结束
        outputStream.write(END_FIX.getBytes());
        outputStream.flush();
        con.connect();
       int responseCode=con.getResponseCode();
     //  con.getHeaderFields()
        if (responseCode == 200) {
            // 获取返回流
           return getResult(con.getInputStream());
        }else {
            //此处判断一下500
            String str=getResult(con.getErrorStream());
            throw new RuntimeException( String.valueOf(responseCode)+":"+str);

        }

    } catch (Exception  e) {
      //  e.printStackTrace();
        throw new RuntimeException("http请求出错 \r\n"+e.getMessage());
    }

}


//此处Stream转字符串
public static String getResult(InputStream inputStream) {
    String result = "";
    ByteArrayOutputStream dataOutputStream = null;
    try {
        byte[] buf = new byte[1024];
        int n;
        dataOutputStream = new ByteArrayOutputStream();

        while (((n = inputStream.read(buf)) != -1)) {
            dataOutputStream.write(buf, 0, n);
        }
        result = new String(dataOutputStream.toByteArray(), "UTF-8");
    } catch (IOException e) {
        e.printStackTrace();
        throw new RuntimeException("获取httpResponse出错 \r\n"+e.getMessage());
    }finally {
        try {
            if(inputStream!=null) inputStream.close();
            if(dataOutputStream!=null)   dataOutputStream.close();
        } catch (IOException e) {

        }
    }

    return result;
}