欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

了解 HTTP 协议中的多art/表单数据

最编程 2024-05-06 14:10:51
...
public class MultipartWriter { private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; private static final byte[] FIELD_SEP = ": ".getBytes(StandardCharsets.ISO_8859_1); private static final byte[] CR_LF = "\r\n".getBytes(StandardCharsets.ISO_8859_1); private static final String TWO_HYPHENS_TEXT = "--"; private static final byte[] TWO_HYPHENS = TWO_HYPHENS_TEXT.getBytes(StandardCharsets.ISO_8859_1); private static final String CONTENT_DISPOSITION_KEY = "Content-Disposition"; private static final String CONTENT_TYPE_KEY = "Content-Type"; private static final String DEFAULT_CONTENT_TYPE = "multipart/form-data; boundary="; private static final String DEFAULT_BINARY_CONTENT_TYPE = "application/octet-stream"; private static final String DEFAULT_TEXT_CONTENT_TYPE = "text/plain;charset=UTF-8"; private static final String DEFAULT_CONTENT_DISPOSITION_VALUE = "form-data; name=\"%s\""; private static final String FILE_CONTENT_DISPOSITION_VALUE = "form-data; name=\"%s\"; filename=\"%s\""; private final Map<String, String> headers = new HashMap<>(8); private final List<AbstractMultipartPart> parts = new ArrayList<>(); private final String boundary; private MultipartWriter(String boundary) { this.boundary = Objects.isNull(boundary) ? TWO_HYPHENS_TEXT + UUID.randomUUID().toString().replace("-", "") : boundary; this.headers.put(CONTENT_TYPE_KEY, DEFAULT_CONTENT_TYPE + this.boundary); } public static MultipartWriter newMultipartWriter(String boundary) { return new MultipartWriter(boundary); } public static MultipartWriter newMultipartWriter() { return new MultipartWriter(null); } public MultipartWriter addHeader(String key, String value) { if (!CONTENT_TYPE_KEY.equalsIgnoreCase(key)) { headers.put(key, value); } return this; } public MultipartWriter addTextPart(String name, String text) { parts.add(new TextPart(String.format(DEFAULT_CONTENT_DISPOSITION_VALUE, name), DEFAULT_TEXT_CONTENT_TYPE, this.boundary, text)); return this; } public MultipartWriter addBinaryPart(String name, byte[] bytes) { parts.add(new BinaryPart(String.format(DEFAULT_CONTENT_DISPOSITION_VALUE, name), DEFAULT_BINARY_CONTENT_TYPE, this.boundary, bytes)); return this; } public MultipartWriter addFilePart(String name, File file) { parts.add(new FilePart(String.format(FILE_CONTENT_DISPOSITION_VALUE, name, file.getName()), DEFAULT_BINARY_CONTENT_TYPE, this.boundary, file)); return this; } private static void writeHeader(String key, String value, OutputStream out) throws IOException { writeBytes(key, out); writeBytes(FIELD_SEP, out); writeBytes(value, out); writeBytes(CR_LF, out); } private static void writeBytes(String text, OutputStream out) throws IOException { out.write(text.getBytes(DEFAULT_CHARSET)); } private static void writeBytes(byte[] bytes, OutputStream out) throws IOException { out.write(bytes); } interface MultipartPart { void writeBody(OutputStream os) throws IOException; } @RequiredArgsConstructor public static abstract class AbstractMultipartPart implements MultipartPart { protected final String contentDispositionValue; protected final String contentTypeValue; protected final String boundary; protected String getContentDispositionValue() { return contentDispositionValue; } protected String getContentTypeValue() { return contentTypeValue; } protected String getBoundary() { return boundary; } public final void write(OutputStream out) throws IOException { writeBytes(TWO_HYPHENS, out); writeBytes(getBoundary(), out); writeBytes(CR_LF, out); writeHeader(CONTENT_DISPOSITION_KEY, getContentDispositionValue(), out); writeHeader(CONTENT_TYPE_KEY, getContentTypeValue(), out); writeBytes(CR_LF, out); writeBody(out); writeBytes(CR_LF, out); } } public static class TextPart extends AbstractMultipartPart { private final String text; public TextPart(String contentDispositionValue, String contentTypeValue, String boundary, String text) { super(contentDispositionValue, contentTypeValue, boundary); this.text = text; } @Override public void writeBody(OutputStream os) throws IOException { os.write(text.getBytes(DEFAULT_CHARSET)); } @Override protected String getContentDispositionValue() { return contentDispositionValue; } @Override protected String getContentTypeValue() { return contentTypeValue; } } public static class BinaryPart extends AbstractMultipartPart { private final byte[] content; public BinaryPart(String contentDispositionValue, String contentTypeValue, String boundary, byte[] content) { super(contentDispositionValue, contentTypeValue, boundary); this.content = content; } @Override public void writeBody(OutputStream out) throws IOException { out.write(content); } } public static class FilePart extends AbstractMultipartPart { private final File file; public FilePart(String contentDispositionValue, String contentTypeValue, String boundary, File file) { super(contentDispositionValue, contentTypeValue, boundary); this.file = file; } @Override public void writeBody(OutputStream out) throws IOException { try (InputStream in = new FileInputStream(file)) { final byte[] buffer = new byte[4096]; int l; while ((l = in.read(buffer)) != -1) { out.write(buffer, 0, l); } out.flush(); } } } public void forEachHeader(BiConsumer<String, String> consumer) { headers.forEach(consumer); } public void write(OutputStream out) throws IOException { if (!parts.isEmpty()) { for (AbstractMultipartPart part : parts) { part.write(out); } } writeBytes(TWO_HYPHENS, out); writeBytes(this.boundary, out); writeBytes(TWO_HYPHENS, out); writeBytes(CR_LF, out); } } 复制代码

推荐阅读