Чтение данных POST из html-формы, отправленной на serversocket

я пытаюсь написать простейшее серверное приложение на Java, отображающее html-форму с вводом текстовой области, которая после отправки дает мне возможность анализировать xml, введенный в этой текстовой области. На данный момент я создаю простой сервер на основе serversocket:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class WebServer {

  protected void start() {
    ServerSocket s;
    String gets = "";
    System.out.println("Start on port 80");
    try {
      // create the main server socket
      s = new ServerSocket(80);
    } catch (Exception e) {
      System.out.println("Error: " + e);
      return;
    }

    System.out.println("Waiting for connection");
    for (;;) {
      try {
        // wait for a connection
        Socket remote = s.accept();
        // remote is now the connected socket
        System.out.println("Connection, sending data.");
        BufferedReader in = new BufferedReader(new InputStreamReader(
            remote.getInputStream()));
        PrintWriter out = new PrintWriter(remote.getOutputStream());

        String str = ".";

        while (!str.equals("")) {
          str = in.readLine();
          if (str.contains("GET")){
            gets = str;
            break;
          }
        }

        out.println("HTTP/1.0 200 OK");
        out.println("Content-Type: text/html");
        out.println("");
        // Send the HTML page
        String method = "get";
        out.print("<html><form method="+method+">");
        out.print("<textarea name=we></textarea></br>");
        out.print("<input type=text name=a><input type=submit></form></html>");
        out.println(gets);
        out.flush();

        remote.close();
      } catch (Exception e) {
        System.out.println("Error: " + e);
      }
    }
  }

  public static void main(String args[]) {
    WebServer ws = new WebServer();
    ws.start();
  }
}

После того, как форма (текстовое поле с xml и одним дополнительным текстовым вводом) отправляется в переменную типа String 'gets', у меня есть значения Urlencoded моих переменных (также отображаемые на экране, это выглядит так:

gets = GET /?we=%3Cnetwork+ip_addr%3D%2210.0.0.0%2F8%22+save_ip%3D%22true%22%3E%0D%0A%3Csubnet+interf_used%3D%22200%22+name%3D%22lan1%22+%2F%3E%0D%0A%3Csubnet+interf_used%3D%22254%22+name%3D%22lan2%22+%2F%3E%0D%0A%3C%2Fnetwork%3E&a=fooBar HTTP/1.1 

Что я могу сделать, чтобы изменить метод GET на POST (если я просто изменю его в форме, а затем поставлю «if (str.contains («POST»)) {», он даст мне строку вроде

gets = POST / HTTP/1.1

без переменных. И после этого, как я могу использовать xml из моего текстового поля (называемого «мы»)?


person qqryq    schedule 13.06.2010    source источник
comment
Привет qqryq. У меня такой же код. Вы поняли, как читать тело POST? Я пытался запустить второй цикл, как говорит cygri, но методы inputStream.read или bufferedReader.readline блокируют мой поток. Как вы читаете тело POST?   -  person Alexmelyon    schedule 12.02.2014
comment
О, я понял! Мне нужно прочитать заголовок Content-Length: и выполнить for-cycle до этой длины.   -  person Alexmelyon    schedule 12.02.2014


Ответы (5)


Поскольку после заголовков есть пустая строка, вот мой относительно простой способ получения данных полезной нагрузки поста после чтения информации заголовка с использованием метода readLine() BufferedReader.

//socket is an instance of Socket
InputStream is = socket.getInputStream();
InputStreamReader isReader = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isReader);

//code to read and print headers
String headerLine = null;
    while((headerLine = br.readLine()).length() != 0){
        System.out.println(headerLine);
    }

//code to read the post payload data
StringBuilder payload = new StringBuilder();
        while(br.ready()){
            payload.append((char) br.read());
            }
System.out.println("Payload data is: "+payload.toString())
person VSarin    schedule 29.11.2015
comment
большое спасибо... это то, что я ищу. . . . - person Mang Jojot; 08.03.2019
comment
Это сработало хорошо. Но он возвращает не только данные, но и полное описание почтового запроса. Есть ли способ получить только данные. или мы должны разделить строку обычным способом? - person SWIK; 10.01.2021

Это моя реализация для чтения тела POST:

try {
    Socket socket = params[0];
    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    // read request
    String line;
    line = in.readLine();
    StringBuilder raw = new StringBuilder();
    raw.append("" + line);
    boolean isPost = line.startsWith("POST");
    int contentLength = 0;
    while (!(line = in.readLine()).equals("")) {
        raw.append('\n' + line);
        if (isPost) {
            final String contentHeader = "Content-Length: ";
            if (line.startsWith(contentHeader)) {
                contentLength = Integer.parseInt(line.substring(contentHeader.length()));
            }
        }
    }
    StringBuilder body = new StringBuilder();
    if (isPost) {
        int c = 0;
        for (int i = 0; i < contentLength; i++) {
            c = in.read();
            body.append((char) c);
            Log.d("JCD", "POST: " + ((char) c) + " " + c);
        }
    }
    raw.append(body.toString());
    publishProgress(raw.toString());
    // send response
    out.write("HTTP/1.1 200 OK\r\n");
    out.write("Content-Type: text/html\r\n");
    out.write("\r\n");
    out.write(new Date().toString());
    if (isPost) {
        out.write("<br><u>" + body.toString() + "</u>");
    } else {
        out.write("<form method='POST'>");
        out.write("<input name='name' type='text'/>");
        out.write("<input type='submit'/>");
        out.write("</form>");
    }
    //
    // do not in.close();
    out.flush();
    out.close();
    socket.close();
    //
} catch (Exception e) {
    e.printStackTrace();
    StringWriter sw = new StringWriter();
    e.printStackTrace(new PrintWriter(sw));
    publishProgress('\n' + sw.toString());
}

Я делаю это для Android, и publishProgres в моем случае означает:

protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
        instance.logTextView.append(values[0]);
    }
person Alexmelyon    schedule 12.02.2014
comment
По сути, первое чтение должно захватывать все строки заголовков. После этого следует использовать заголовок Content-Length, чтобы заранее узнать, сколько символов следует прочитать, а затем просто перейти к дальнейшей обработке. - person prash; 08.09.2016

Типичный HTTP-запрос POST выглядит следующим образом:

POST / HTTP/1.1
Host: www.example.com
Accept: text/html,*/*;q=0.5
User-Agent: BrowserName/1.0
Referer: http://www.example.com/
Content-type: application/x-www-form-urlencoded; charset=utf-8

foo=1&bar=2

Первая строка содержит метод (обычно GET или POST, но есть и другие, например HEAD, PUT, DELETE), URI запроса и версию протокола. Затем идет ряд заголовков запросов, которые могут быть не так важны для простого сервера. Если метод принимает тело запроса (POST и PUT), то после заголовков есть пустая строка, за которой следует тело запроса. В случае POST из HTML-формы тело будет состоять из key=value пар для всех элементов формы, соединенных &. Значения будут закодированы в %.

Вам просто нужно позаботиться о правильном анализе всего запроса.

Вы должны знать, что окончания строк в HTTP должны быть в стиле Windows (\r\n). Метод readline() может интерпретировать это как два разрыва строки, поэтому может показаться, что между каждой из реальных строк есть пустая строка.

person cygri    schedule 13.06.2010
comment
хорошо, но как получить эти данные, когда мое время останавливается на первой пустой строке? - person qqryq; 14.06.2010
comment
Перепишите цикл while так, чтобы он не останавливался на первой строке. Вам нужна помощь с этим? - person cygri; 15.06.2010

Данные POST не находятся в первой строке. Напечатайте все строки, и вы увидите. Это на самом деле сразу после пустой строки.

person irreputable    schedule 13.06.2010
comment
хорошо, но как я могу вывести все, если у меня есть инструкция 'while (!str.equals()) {'? Игнорировать первую пустую строку и остановиться на другой? - person qqryq; 14.06.2010

Из этого -

Нам нужно сначала прочитать заголовки, а затем снова прочитать из того же BufferedReader, используя фактическую длину содержимого, указанную в разделе заголовка:

BufferedReader in = new BufferedReader(new InputStreamReader(is));
String line;
line = in.readLine();
while ((line = in.readLine()) != null && (line.length() != 0)) {
    System.out.println("HTTP-HEADER: " + line);
    if (line.indexOf("Content-Length:") > -1) {
    postDataI = new Integer(
        line.substring(
            line.indexOf("Content-Length:") + 16,
            line.length())).intValue();
    }
}
String postData = "";
// read the post data
if (postDataI > 0) {
    char[] charArray = new char[postDataI];
    in.read(charArray, 0, postDataI);
    postData = new String(charArray);
}

ХТН

person prash    schedule 08.09.2016