HTTP POSTing в Java без библиотек - PullRequest
0 голосов
/ 04 марта 2012

Я бы хотел, без библиотек, POST-файл для сценария PHP на Java.

Вот как будет выглядеть HTML, если бы он действительно имел форму:

<form action="http://example.com/upload.php" method="post" enctype="multipart/form-data" name="input">
<input type="file" name="image" /><input type="submit" value="Upload file"  />

Тогда я могу просто взять его / всю информацию, которая поставляется в PHP с $_FILES["image"].

Если бы у меня был файл example.png (файлы всегда будут PNG, если это важно), я хотел бы загрузитьКак мне это сделать?

Я полагаю, что самый простой способ реализовать это - создать функцию, которая принимает File, строку URL, и я предполагаю другое имя строки, потому что мы не должны предполагатьмы всегда хотим POST с именем image.Он отправит файл на этот URL под этим именем и вернет строку того, что URL вернул после предполагаемого успеха.

Ответы [ 5 ]

1 голос
/ 04 марта 2012

Проверьте эту статью для кода, который делает именно то, что вы описываете без сторонних библиотек.Удачи !!

0 голосов
/ 10 ноября 2013

Я только что написал это в другом посте.:)

Я только что добавил это в Boon для кого-то еще.Благо мало.А служебный класс 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

Теперь вы можете сделать это за один вызов метода.:)

:)

Вы можете вырезать и вставить код в свой проект.Существует один служебный класс, который называется HTTP, который использует стандартный класс URL из Java.

Позвольте мне рассказать вам об этом.(Вы можете взять его здесь: btw: http://richardhightower.github.io/site/Boon/Welcome.html)

Я добавил это к благу, основываясь на этом посте ( Http Post и строковые и двоичные параметры в Java ):

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.

Кстати, карта - это всего лишь служебный метод, который создает карту (перечисление внизу).

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 he.xdigit.

Тогда у вас есть только два способа завершить кодирование:

/**
 * 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, но прост в использовании и очень быстр.У меня есть ориентиры.:)

Что я пропустил?

Дайте мне знать, если это работает для вас.

- Рик

Функция карты - это просто служебные методытак что я могу кратко представить карту, так как я часто их использую.Это идет только до 9 или десяти.Помимо этого у меня есть способ передать список записей.

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;
}
0 голосов
/ 04 марта 2012

Для отладки запроса и ответа вы можете использовать такую ​​программу, как Fiddler, для просмотра тела POST, когда это делает браузер, и когда это делает клиент java.В вашем клиенте установите системное свойство java.net.useSystemProxies в значение true, чтобы при отладке он использовал Fiddler.

Если вы закодируете свое тело как составное, PHP поместит файл в $ _FILES.Если вы не используете многочастное кодирование, тогда ваш Java-код будет намного проще, но тогда ваш PHP-код должен вручную обработать данные POST и сохранить файл на стороне сервера.Это также будет более эффективным, потому что кодирование увеличивает объем данных, которые должны быть отправлены.Я бы предпочел не кодировать, а просто отправлять данные, потому что я считаю, что кодировка будет трудной, и я не думаю, что код PHP для ручной обработки данных POST будет таким хитрым.

Похоже, что выможет получить доступ к $ HTTP_RAW_POST_DATA, чтобы получить данные POST в PHP.Если файлы, которые нужно загрузить, очень большие, это не сработает.Возможен и другой способ.

РЕДАКТИРОВАТЬ:

В принятом ответе показано, как создать составной POST с использованием Java: Использование java.net.URLConnection для запуска и обработки HTTP-запросов

0 голосов
/ 04 марта 2012

Вы действительно имеете в виду Java или JavaScript? Так как вы упомянули Java, я следую за этим ...

Я думаю, что самым простым способом было бы получить файл в правильно сформированную строку, кодировать его во что-то, что хорошо для транспорта (например, Base64, который не очень сложен для самостоятельной реализации, если вы не хотите использовать библиотеки) и затем вы можете выполнить POST-запрос, отправив правильный HTTP-запрос самостоятельно.

Это не так сложно, но это слишком много, чтобы объяснить здесь, в StackOverflow. Я имею в виду, по крайней мере, для отправки этих HTTP-заголовков действительно рекомендуется использовать библиотеки Java.

0 голосов
/ 04 марта 2012

Я понимаю, что вы указали, что не используете библиотеки, но я бы порекомендовал Apache HttpComponents HttpClient .

Одна из проблем, с которой вы столкнетесь, - это кодирование вашего файла для включения в ваш пост.

...