对于multipart/form-data 来说,许多初次使用这个POST请求格式的同学都会用很长的时间去进行搜索如何使用。
multipart/form-data 这种格式是一种比较特殊的格式,简单来说,就是request请求体在解析后完完全全是一个字符串,中间可能包含了文件的二进制字节流。
因此,在后台解析的过程中,可以很明白的看到一个问题,就是后台要从requestbody中的字符串中取出相关的数据,因此,格式!格式!格式!是非常重要的。
老夫在2022年9月16日这一天,就在处理这个格式的问题。
一下代码可以在后台进行成功的解析。已经进行了标注。有需要的同学可以借鉴一下。
package controller;
import javax.swing.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
public class POST_MultiData {
public static void main(String[] args) {
try {
URL url = new URL("http://localhost:8080/test/POST");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 构建请求头,请求头是随便构建的,任何的字符串都可以。一般来说,以 - 为开头。
String boundary = "-------------" + System.currentTimeMillis();
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
OutputStream outputStream = conn.getOutputStream();
StringBuilder sb = new StringBuilder();
String newLine = "\r\n";
String boundaryPrefix = "--";
sb.append(newLine); //此处注意,作为开头,是可以,将newline省去的,也就是不以 "\r\n"为开头,也可以解析。
sb.append(boundaryPrefix); //此处注意,作为boundaryPrefix 的--, 是不可以省略的,且 boundaryPrefix,必须为 -- 。
sb.append(boundary); //此处注意,作为multipart/form-data的格式,是以boundary为开头,之后为内容的。也就是在每一段内容的开头,都是boundary,此处boundary不可以省略。
sb.append(newLine); //此处注意,boundary之后要有一个回车换行,也就是“\r\n”,因为此处的stringbuild为用代码组织的形式,并不是实际的string的样子,因此常常会马虎而遗忘调一个回车换行,如果确实,解析就会失败。
sb.append("Content-Disposition:form-data;name=\"to\""); //此处规定传输的内容,其中,Content-Dispositon:form-data; 是固定的,name规定的是健的名字,如果是文件还可以跟文件名。网上的参考很多。
sb.append(newLine); //此处注意,Content-Dispostion之后必须要有一个回车换行,否则是无法解析的。且会返回500,服务器报错。
sb.append("Content-Type: text/plain");
sb.append(newLine); //此处注意,在以上的格式声明后,还是需要一个回车换行的,否则还是报错。也就是,内容键的声明和内容之间要有一个换行。这个是必须的,否则会500服务器报错。
sb.append(newLine);
sb.append(newLine); //此处的回车换行是可以加几个都可以的。但是,必须要至少有一个,且之后的回车都会被认为是内容中的!!!也就是至少要有一个空行!!
sb.append("www");
//sb.append(newLine); //此处的回车换行是可以换很多的。这并不会导致解析失败。反而都会被认为是内容中的。。。这个要注意,也就是至少要有一个,其他的都是内容。
//sb.append(newLine);
//sb.append(newLine);
//sb.append(newLine);
//sb.append(newLine);
//sb.append(newLine); //此处为测试用。
//sb.append(newLine);
//sb.append(newLine);
//sb.append(newLine);
//sb.append(newLine);
//sb.append(newLine);
//sb.append("dwed"); //此处用以测试空行会如何识别。
sb.append(newLine); //此处的换行也是不允许省略的,否则是报错,这个很好理解。因为内容要以回车换行来标注分隔。
sb.append(boundaryPrefix); //不可省略,否则报错。
sb.append(boundary); //此处为结尾的boundary,不可省略。
//sb.append(boundaryPrefix); //且结尾的boundary后还要跟一个prifix。但是这个prifix 是可以省略的。
System.out.println(sb);
outputStream.write(sb.toString().getBytes());
outputStream.flush();
outputStream.close(); //关与不关,都是可以发送的。
//above is very important code.
//总结一下就是,在boundary之前,会有 -- ,作为一种保险的识别。
//两个重点,一个是格式声明之后,必须要跟一个回车换行。其次是,格式声明和正式内容之间,有一个空行。
//开头和结尾,都是要用boundary的。但是结尾的--可以不用。
System.out.println("done");
System.out.println(conn.getResponseCode());
}catch (Exception e){
System.out.println("something wrong");
System.out.println(e);
}
}
}