我希望在java中發佈一個包含字符串和二進制參數的表單,例如Http在Java中發佈字符串和二進制參數
名= SAM &照片= < ...二進制數據...>
不幸的是,現有的文件只包括上載字符串或二進制數據分開。我怎麼能結合這兩個?
我希望在java中發佈一個包含字符串和二進制參數的表單,例如Http在Java中發佈字符串和二進制參數
名= SAM &照片= < ...二進制數據...>
不幸的是,現有的文件只包括上載字符串或二進制數據分開。我怎麼能結合這兩個?
您需要發送MIME類型的「application/x-www-form-urlencoded」。這些字段必須是文本。
的字段名稱和值被轉義/編碼,例如空格字符由+', reserved characters are escaped using URL encoding. Oh and that is not all... Non-alphanumeric characters are replaced by
%HH」替換爲20%空間
代表字符的ASCII碼所以兩個十六進制數字。
如果只有Java原本一些如何爲你做這個.....哦,等一下它可以...
不過是一個新的類。自從Java 1.0以來,它一直存在。
查看URLEncoder,它是HTML表單編碼的實用工具類。
該類包含將字符串轉換爲application/x-www-form-urlencoded MIME格式的靜態方法。您可以通過查閱HTML規範(下面引用)來了解關於HTML表單編碼的更多信息。
http://docs.oracle.com/javase/1.4.2/docs/api/java/net/URLEncoder.html
的URLEncoder的處理如下: 「字母數字字符 」a「 到 」z「, 」A「 到 」Z「 和 」0「 至 」9「 保持不變的特殊字符」。 。「,」 - 「,」*「和」_「保持不變。」空格字符「」被轉換爲加號「+」。 「
這裏是踢球二進制...
」所有其他字符是不安全的,並且首先被轉換成使用一些編碼方案的一個或多個字節。然後每個字節由3個字符的字符串「%xy」表示,其中xy是該字節的兩位十六進制表示。推薦使用的編碼方案是UTF-8。然而,爲了兼容性的原因,如果未指定編碼,則使用平臺的默認編碼。」
指定UTF-8總是。
這裏是HTTP規範。
我只是說這恩賜給你的。
http://richardhightower.github.io/site/Boon/Welcome.html
String response = HTTP.postForm ("http://localhost:9220/test",
Collections.EMPTY_MAP,
map("hI", (Object)"hi-mom", "image", new byte[] {1,2,3})
);
https://github.com/RichardHightower/boon
現在你可以在一個方法調用中做到這一點。 :)
:)
讓我爲你分手。(你可以在這裏抓住它BTW:http://richardhightower.github.io/site/Boon/Welcome.html)
我說這福音:
public static String postForm(final String url, final Map<String, ?> headers,
final Map<String, Object> formData
)
這裏的關鍵是編碼的二進制數據:
String response = HTTP.postForm ("http://localhost:9220/test",
Collections.EMPTY_MAP,
map("hI", (Object)"hi-mom", "image", new byte[] {1,2,3})
);
boolean ok = true;
ok |= response.startsWith ("hI=hi-mom&image=%01%02%03\n") ||
die("encoding did not work");
上面是測試顯示它的工作原理據我瞭解的規格。
關鍵是它將圖像,新字節[] {1,2,3}變成圖像\ u0000 =%01%02%03。
BTW地圖只是一個創建地圖(列在底部)的實用方法。
http服務器只是一個回聲。
return Exceptions.tryIt(String.class, new Exceptions.TrialWithReturn<String>() {
@Override
public String tryIt() throws Exception {
URLConnection connection;
connection = doPostFormData(url, headers, formData);
return extractResponseString(connection);
}
});
神奇發生在doPostFormData:
private static URLConnection doPostFormData(String url, Map<String, ?> headers,
Map<String, Object> formData
) throws IOException {
HttpURLConnection connection;/* Handle output. */
connection = (HttpURLConnection) new URL(url).openConnection();
connection.setConnectTimeout(DEFAULT_TIMEOUT_SECONDS * 1000);
connection.setDoOutput(true);
connection.addRequestProperty ("Content-Type", "application/x-www-form-urlencoded");
ByteBuf buf = ByteBuf.create (244);
final Set<String> keys = formData.keySet();
int index = 0;
for (String key : keys) {
Object value = formData.get (key);
if (index > 0) {
buf.addByte ('&');
}
buf.addUrlEncoded ( key );
buf.addByte ('=');
if (! (value instanceof byte[])) {
buf.addUrlEncoded (value.toString());
} else {
buf.addUrlEncodedByteArray((byte[]) value);
}
index++;
}
manageContentTypeHeaders ("application/x-www-form-urlencoded",
StandardCharsets.UTF_8.name(), connection);
manageHeaders(headers, connection);
int len = buf.len();
IO.write(connection.getOutputStream(),
new String(buf.readForRecycle(), 0, len, StandardCharsets.UTF_8), IO.DEFAULT_CHARSET);
return connection;
}
通知調用addUrlEncodedByteArray你傳遞一個字節數組。 Java可以正常使用字符串的URL編碼。我找不到一個簡單的方法 來編碼一個字節數組,所以我只寫了它。
public void addUrlEncodedByteArray (byte[] value) {
final byte[] encoded = new byte [2];
for (int index = 0; index < value.length; index++) {
int i = value[index];
if (i >= 'a' && i <= 'z') {
this.addByte (i);
} else if (i >= 'A' && i <= 'Z') {
this.addByte (i);
} else if (i >= '0' && i <= '9') {
this.addByte (i);
} else if (i == '_' || i == '-' || i == '.' || i == '*') {
this.addByte (i);
} else if (i == ' ') {
this.addByte ('+');
} else {
encodeByteIntoTwoAsciiCharBytes(i, encoded);
this.addByte ('%');
this.addByte (encoded [0]);
this.addByte (encoded [1]);
}
}
}
它不是最漂亮的。但單元測試工作。 我相信你會得到主意。它遵循規範並相應地轉換。
不在一定範圍內的所有數據都使用%hexdigit hexdigit進行編碼。
然後你只需要這兩種方法完成了編碼:
/**
* Turns a single nibble into an ascii HEX digit.
*
* @param nibble the nibble to encode.
*
* @return the encoded nibble (1/2 byte).
*/
protected static int encodeNibbleToHexAsciiCharByte(final int nibble) {
switch (nibble) {
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
return nibble + 0x30; // 0x30('0') - 0x39('9')
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
return nibble + 0x57; // 0x41('a') - 0x46('f')
default:
die("illegal nibble: " + nibble);
return -1;
}
}
/**
* Turn a single bytes into two hex character representation.
*
* @param decoded the byte to encode.
* @param encoded the array to which each encoded nibbles are now ascii hex representations.
*/
public static void encodeByteIntoTwoAsciiCharBytes(final int decoded, final byte[] encoded) {
Objects.requireNonNull (encoded);
boolean ok = true;
ok |= encoded.length == 2 || die("encoded array must be 2");
encoded[0] = (byte) encodeNibbleToHexAsciiCharByte((decoded >> 4) & 0x0F);
encoded[1] = (byte) encodeNibbleToHexAsciiCharByte(decoded & 0x0F);
}
這是最重要的位。剩下的就是處理HTTP請求/頭文件gak。
這裏是manageContentTypeHeaders
manageContentTypeHeaders ("application/x-www-form-urlencoded",
StandardCharsets.UTF_8.name(), connection);
...
private static void manageContentTypeHeaders(String contentType, String charset, URLConnection connection) {
connection.setRequestProperty("Accept-Charset", charset == null ? StandardCharsets.UTF_8.displayName() : charset);
if (contentType!=null && !contentType.isEmpty()) {
connection.setRequestProperty("Content-Type", contentType);
}
}
下面是管理標題
manageHeaders(headers, connection);
...
private static void manageHeaders(Map<String, ?> headers, URLConnection connection) {
if (headers != null) {
for (Map.Entry<String, ?> entry : headers.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue().toString());
}
}
}
然後我們編碼流與UTF_8派:
int len = buf.len();
IO.write(connection.getOutputStream(),
new String(buf.readForRecycle(), 0, len, StandardCharsets.UTF_8), IO.DEFAULT_CHARSET);
的IO寫只是做這個: IO.write ...
public static void write (OutputStream out, String content, Charset charset) {
try (OutputStream o = out) {
o.write (content.getBytes (charset));
} catch (Exception ex) {
Exceptions.handle (ex);
}
}
ByteBuf就像一個ByteBuffer,但更易於使用且速度非常快。我有基準。 :)
我錯過了什麼?
讓我知道它是否適合你。
--Rick
地圖功能只是實用方法,所以我可以簡明地表示地圖,因爲我覺得我用他們很多。它只會達到9或10。除此之外,我有一種方式來傳遞條目列表。
public static <K, V> Map<K, V> map(K k0, V v0) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1, K k2, V v2) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
map.put(k2, v2);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1, K k2, V v2, K k3,
V v3) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
map.put(k2, v2);
map.put(k3, v3);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1, K k2, V v2, K k3,
V v3, K k4, V v4) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
map.put(k2, v2);
map.put(k3, v3);
map.put(k4, v4);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1, K k2, V v2, K k3,
V v3, K k4, V v4, K k5, V v5) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
map.put(k2, v2);
map.put(k3, v3);
map.put(k4, v4);
map.put(k5, v5);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1, K k2, V v2, K k3,
V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
map.put(k2, v2);
map.put(k3, v3);
map.put(k4, v4);
map.put(k5, v5);
map.put(k6, v6);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1, K k2, V v2, K k3,
V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
map.put(k2, v2);
map.put(k3, v3);
map.put(k4, v4);
map.put(k5, v5);
map.put(k6, v6);
map.put(k7, v7);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1, K k2, V v2, K k3,
V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
map.put(k2, v2);
map.put(k3, v3);
map.put(k4, v4);
map.put(k5, v5);
map.put(k6, v6);
map.put(k7, v7);
map.put(k8, v8);
return map;
}
public static <K, V> Map<K, V> map(K k0, V v0, K k1, V v1, K k2, V v2, K k3,
V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8,
K k9, V v9) {
Map<K, V> map = new LinkedHashMap<>(10);
map.put(k0, v0);
map.put(k1, v1);
map.put(k2, v2);
map.put(k3, v3);
map.put(k4, v4);
map.put(k5, v5);
map.put(k6, v6);
map.put(k7, v7);
map.put(k8, v8);
map.put(k9, v9);
return map;
}
的
可能重複[HTTP POST在Java中(文件上傳)(http://stackoverflow.com/questions/9692166/http-post-in-java-with-file-upload) – tucuxi
使用Apache Commons HTTPRequest - 手動完成是一件非常麻煩的事情。您將發送多部分請求,並且每個部分都可以擁有自己的數據。 – tucuxi
apache庫如此混亂以至於建議的解決方案似乎無法正常工作。 –