Пустая строка в ответ от сервера Java

431
21 декабря 2016, 00:17

Есть вот такой код

import java.io.*;
import java.net.Socket;
import java.text.ParseException;
import static java.lang.Thread.sleep;
public class HttpClient {
    public static void main(String[] args) {
        try {
            String header = null;
            if (args.length == 0) {
                header = readHeader(System.in);
            } else {
                FileInputStream fis = new FileInputStream(args[0]);
                header = readHeader(fis);
                fis.close();
            }
            //System.out.println("Заголовок: \n" + header);
   /* Запрос отправляется на сервер и мы получаем ответ*/
            String answer = sendRequest(header);
   /* Ответ выводится на консоль */
            System.out.println("Ответ от сервера: \n");
            System.out.write(answer.getBytes());
        } catch (Exception e) {
            System.err.println(e.getMessage());
            e.getCause().printStackTrace();
        }
    }
    /**
     * Читает поток и возвращает его содержимое в виде строки.
     */
    public static String readHeader(InputStream strm) throws IOException {
        byte[] buff = new byte[64 * 1024];
        int length = strm.read(buff);
        String res = new String(buff, 0, length);
        return res;
    }
    /**
     * Отправляет запрос в соответствии с Http заголовком.
     *
     * @return ответ от сервера.
     */
    public static String sendRequest(String httpHeader) throws Exception {
  /* Из http заголовка берется арес сервера */
        String host = null;
        int port = 0;
        try {
            host = getHost(httpHeader);
            port = getPort(host);
            host = getHostWithoutPort(host);
        } catch (Exception e) {
            throw new Exception("Не удалось получить адрес сервера.", e);
        }
  /* Отправляется запрос на сервер */
        Socket socket;
        try {
            socket = new Socket(host, port);
            System.out.println("Создан сокет: " + host + " port:" + port);
            OutputStream os = socket.getOutputStream();
            os.write(httpHeader.getBytes());
            os.flush();
            System.out.println("Заголовок отправлен. \n");
        } catch (Exception e) {
            throw new Exception("Ошибка при отправке запроса: " + e.getMessage(), e);
        }
  /* Ответ от сервера записывается в результирующую строку */
        String res = null;
        try {
            BufferedReader bfr = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            StringBuffer sbf = new StringBuffer();
            int ch = bfr.read();
            while (ch != -1) {
                sbf.append((char) ch);
                ch = bfr.read();
            }
            res = sbf.toString();
        } catch (Exception e) {
            throw new Exception("Ошибка при чтении ответа от сервера.", e);
        }
        socket.close();
        return res;
    }
    /**
     * Возвращает имя хоста (при наличии порта, с портом) из http заголовка.
     */
    private static String getHost(String header) throws ParseException {
        final String host = "Host: ";
        final String normalEnd = "\n";
        final String msEnd = "\r\n";
        int s = header.indexOf(host, 0);
        if (s < 0) {
            return "localhost";
        }
        s += host.length();
        int e = header.indexOf(normalEnd, s);
        e = (e > 0) ? e : header.indexOf(msEnd, s);
        if (e < 0) {
            throw new ParseException(
                    "В заголовке запроса не найдено " +
                            "закрывающих символов после пункта Host.",
                    0);
        }
        String res = header.substring(s, e).trim();
        return res;
    }
    /**
     * Возвращает номер порта.
     */
    private static int getPort(String hostWithPort) {
        int port = hostWithPort.indexOf(":", 0);
        port = (port < 0) ? 80 : Integer.parseInt(hostWithPort
                .substring(port + 1));
        return port;
    }
    /**
     * Возвращает имя хоста без порта.
     */
    private static String getHostWithoutPort(String hostWithPort) {
        int portPosition = hostWithPort.indexOf(":", 0);
        if (portPosition < 0) {
            return hostWithPort;
        } else {
            return hostWithPort.substring(0, portPosition);
        }
    }
}

Заголовок:

HEAD http://www.w3.org/standvgbuards/webdesign/htmlcss HTTP/1.1
Host: www.w3.org
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
Referer: http://localhost/
Accept-Language: ru
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)

В ответ от сервера приходит пустая строка. Почему?

Answer 1

Протокол HTTP подразумевает, что в каждом сообщении есть мета-информация (первая строка + заголовки) и непосредственно тело (может быть пустым). Для отделения одного от другого используется два перевода строки, без которых целевой сервер не знает, что мета-информация закончилась. Об окончании запроса он может узнать только тогда, когда вы оборвете подключение, и поэтому не сможет прислать ответ.

Поэтому вам, как минимум, надо предоставить эти два перевода строки. Этого тоже может оказаться недостаточно, если сервер "не понимает", что у HEAD-запроса не должно быть тела. В этом случае вы попадаете в одну из плохих частей HTTP-протокола - сервер не знает, когда кончится ваш запрос, поэтому вам надо будет подсказать ему одним из трех способов:

  • Реализовать chunk transfer encoding и корректно завершить передачу пустым чанком
  • Добавить заголовок Content-Length: 0
  • Открыто заявить о завершении передачи с клиентской стороны, вызвав передачу TCP-пакета с проставленным FIN-битом (не владею сокетной магией в джаве на должном уровне, поэтому не подскажу как)
Answer 2

Оказывается надо в конце заголовка ставить перенос строки. ('\n') Как говориться: "И всё из-за этой фигни?"

READ ALSO
Использование hazelcast java клиента

Использование hazelcast java клиента

Кто знает, разумно ли использовать hazelcast java client на клиентской стороне для подключения к hazelcast кластеру, или следует использовать только для...

272
Не отображается изображения при помощи Picasso

Не отображается изображения при помощи Picasso

Необходимо в галерее выбрать изображения и вывести их в imageViewЗапуск intenta:( библиотека)

378
Как пишут игры с подключением к серверу?

Как пишут игры с подключением к серверу?

Допустим, нужно реализовать игру - мультиплеер по сетиДопустим, крестики-нолики

248