Как я могу отправить HTTP-ответ, используя только стандартные сетевые библиотеки? - PullRequest
0 голосов
/ 13 сентября 2010

Я работаю над своим первым домашним проектом в классе веб-программирования, который заключается в написании простого веб-сервера на Java. Я нахожусь в точке, где у меня есть данные, которые передаются взад и вперед, и на первый взгляд, мой детский сервер, кажется, работает нормально. Однако я не могу найти способ отправить соответствующие ответы. (Другими словами, неверный запрос страницы показал бы страницу HTML размером 404 дюйма, но он все равно возвращает статус 200 OK, когда я просматриваю заголовки ответа).

Я ограничен возможностью использовать стандартные сетевые библиотеки для управления сокетами и стандартные библиотеки ввода / вывода для чтения и записи байтов и строк из входного потока. Вот соответствующий код:

С моей главной ...

            ServerSocket servSocket = new ServerSocket(port, 10);           // Bind the socket to the port
        System.out.println("Opened port " + port + " successfully!");

                while(true) {
            //Accept the incoming socket, which means that the server process will
            //wait until the client connects, then prepare to handle client commands
            Socket newDataSocket = servSocket.accept();
            System.out.println("Client socket created and connected to server socket...");

            handleClient(newDataSocket);                                //Call handleClient method
        }   

Из метода handleClient ... (внутри цикла, который анализирует метод запроса и путь)

                    if(checkURL.compareTo("/status") == 0)  {   // Check to see if status page has been requested
                    System.out.println("STATUS PAGE");      // TEMPORARY. JUST TO MAKE SURE WE ARE PROPERLY ACCESSING STATUS PAGE
                    sendFile("/status.html", dataStream);
                }
                else {
                    sendFile(checkURL, dataStream);         // If not status, just try the input as a file name
                }

Из метода sendFile ...

        File f = new File(where);                                               // Create the file object
    if(f.exists() == true) {                                                        // Test if the file even exists so we can handle a 404 if not.
        DataInputStream din;
        try {
            din = new DataInputStream(new FileInputStream(f));
            int len = (int) f.length();                                     // Gets length of file in bytes
            byte[] buf = new byte[len];
            din.readFully(buf);
            writer.write("HTTP/1.1 200 OK\r\n");                            // Return status code for OK (200)
            writer.write("Content-Length: " + len + "\r\n");                // WAS WRITING TO THE WRONG STREAM BEFORE!
            writer.write("Content-Type: "+type+"\r\n\r\n\r\n");             // TODO VERIFY NEW CONTENT-TYPE CODE
            out.write(buf);                                                 // Writes the FILE contents to the client
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();                                            // Not really handled since that's not part of project spec, strictly for debug.
        }
    }
    else {
        writer.write("HTTP/1.1 404 Not Found\r\n");                         // Attempting to handle 404 as simple as possible.
        writer.write("Content-Type: text/html\r\n\r\n\r\n");
        sendFile("/404.html", sock);
    }

Кто-нибудь может объяснить, как в условном от sendFile я могу изменить ответ в блоке 404 (как я уже говорил, заголовки ответа все еще показывают 200 OK)? Это выводит меня из себя, и я просто хочу использовать класс HTTPResponse, но не могу. (Кроме того, длина и тип содержимого не отображаются, если f.exists == true.)

Спасибо!

Ответы [ 3 ]

3 голосов
/ 13 сентября 2010

Редактировать Мне кажется, что в ситуации 404, вы отправляете что-то вроде этого:

HTTP/1.1 404 Not Found
Content-Type: text/html
HTTP/1.1 200 OK
Content-Length: 1234
Content-Type: text/html

... сопровождаемый 404 страницей. Обратите внимание на строку 200, следующую за 404. Это потому, что ваша обработка 404 вызывает sendFile, который выводит код состояния ответа 200. Это, вероятно, сбивает с толку получателя.

Старый ответ, который пропустил, что:

HTTP-ответ начинается со строки состояния, за которой (необязательно) следует серия заголовков, а затем (необязательно) включает тело ответа. Строка состояния и заголовки - это просто строки в определенном формате, например (для выбора случайного примера):

HTTP/1.0 404 Not Found

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

Также может быть полезно сделать такие вещи из вашей любимой командной строки:

telnet www.google.com 80
GET /thispagewontbefound

... и нажмите Enter. Вы получите что-то вроде этого:

HTTP/1.0 404 Not Found
Content-Type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sun, 12 Sep 2010 23:01:14 GMT
Server: sffe
Content-Length: 1361
X-XSS-Protection: 1; mode=block

... сопровождаемый некоторым HTML, чтобы обеспечить дружественную страницу 404. Первая строка выше - это строка состояния, остальные - заголовки. Между строкой статуса / заголовками и первой строкой содержимого (например, страница) есть пустая строка.

2 голосов
/ 13 сентября 2010

Проблема, которую вы видите, скорее всего, связана с отсутствием flush() на вашем writer. В зависимости от того, какой тип Writer вы используете, байты сначала записываются в буфер, который необходимо сбросить в поток. Это объясняет, почему Content-Length и Content-Type отсутствуют в выводе. Просто очистите его перед записью дополнительных данных в поток.

Далее звоните sendFile("/404.html", sock);. Вы не разместили здесь полный метод, но я полагаю, что вы вызываете его рекурсивно внутри sendFile и таким образом отправляете статус 200 OK для своего файла /404.html.

0 голосов
/ 13 сентября 2010

Исходя из ваших симптомов, я думаю, что реальная проблема в том, что вы вообще не разговариваете со своим сервером!Доказательством является то, что 1) вы не можете получить ответ 404, и 2) ответ 200 не имеет длины и типа контента.Ничто из этого не должно быть возможным ... если вы действительно говорите с кодом, указанным выше.

Возможно:

  • вы говорите со старой версией вашего кода;то есть что-то идет не так в вашем цикле сборки / развертывания,
  • вы (ошибочно) пытаетесь развернуть / запустить свой код в веб-контейнере (Jetty, Tomcat и т. д.) или
  • на вашемклиентский код / ​​браузер фактически общается с другим сервером из-за проксирования, неправильного URL-адреса или чего-то в этом роде.

Я предлагаю вам добавить некоторые следы печати / регистрации в соответствующих точках вашего кода, чтобы подтвердить, что он действительно вызывается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...