Как получить строку запроса в GET с помощью Java HttpServer/HttpExchange?

Я пытаюсь создать простой HttpServer на Java для обработки запросов GET, но когда я пытаюсь получить параметры GET для запроса, я заметил, что класс HttpExchange не имеет для этого метода.

Кто-нибудь знает простой способ прочитать параметры GET (строка запроса)?

Вот как выглядит мой обработчик:

public class TestHandler{
  @Override
  public void handle(HttpExchange exc) throws IOxception {
    String response = "This is the reponse";
    exc.sendResponseHeaders(200, response.length());

    // need GET params here

    OutputStream os = exc.getResponseBody();
    os.write(response.getBytes());
    os.close();
  } 
}

.. и основной метод:

public static void main(String[] args) throws Exception{
  // create server on port 8000
  InetSocketAddress address = new InetSocketAddress(8000);
  HttpServer server = new HttpServer.create(address, 0);

  // bind handler
  server.createContext("/highscore", new TestHandler());
  server.setExecutor(null);
  server.start();
}

person Tibor    schedule 24.07.2012    source источник
comment
Легкий способ? Разобрать URI; это просто запрос на получение. Если вам нужно обрабатывать сообщения, такие вещи, как это может помочь.   -  person Dave Newton    schedule 25.07.2012


Ответы (4)


Следующее: httpExchange.getRequestURI().getQuery()

вернет строку в формате, подобном этому: "field1=value1&field2=value2&field3=value3..."

поэтому вы можете просто разобрать строку самостоятельно, вот как может выглядеть функция для синтаксического анализа:

public Map<String, String> queryToMap(String query) {
    if(query == null) {
        return null;
    }
    Map<String, String> result = new HashMap<>();
    for (String param : query.split("&")) {
        String[] entry = param.split("=");
        if (entry.length > 1) {
            result.put(entry[0], entry[1]);
        }else{
            result.put(entry[0], "");
        }
    }
    return result;
}

И вот как вы могли бы его использовать:

Map<String, String> params = queryToMap(httpExchange.getRequestURI().getQuery()); 
System.out.println("param A=" + params.get("A"));
person anon01    schedule 04.07.2013
comment
Важно знать: запрос может быть нулевым. Вы должны проверить это. - person MinecraftShamrock; 07.04.2014
comment
Спасибо за этот ответ! Однако это не работает для параметров, значение которых включает амперсанд. Чтобы исправить это, используйте getRawQuery() вместо getQuery(), затем param = java.net.URLDecoder.decode(param, "UTF-8") после разделения на &. - person Evan; 17.01.2016
comment
@ Эван, я считаю, что декодирование должно происходить при помещении значения в карту - таким образом вы не потеряете часть значения, если в нем есть «=». - person Gurusharan S; 27.12.2016
comment
Это неправильно декодирует строки, нужно было использовать URLDecoder. - person Oliv; 12.01.2017
comment
Это должно быть param.split("=", 2);, если значение содержит =. (кстати, это решение не поддерживает двойные ключи, такие как x=111&x=222) - person Datz; 30.10.2018

Этот ответ, в отличие от annon01, правильно декодирует ключи и значения. Он не использует String.split, а сканирует строку, используя indexOf, что быстрее.

public static Map<String, String> parseQueryString(String qs) {
    Map<String, String> result = new HashMap<>();
    if (qs == null)
        return result;

    int last = 0, next, l = qs.length();
    while (last < l) {
        next = qs.indexOf('&', last);
        if (next == -1)
            next = l;

        if (next > last) {
            int eqPos = qs.indexOf('=', last);
            try {
                if (eqPos < 0 || eqPos > next)
                    result.put(URLDecoder.decode(qs.substring(last, next), "utf-8"), "");
                else
                    result.put(URLDecoder.decode(qs.substring(last, eqPos), "utf-8"), URLDecoder.decode(qs.substring(eqPos + 1, next), "utf-8"));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e); // will never happen, utf-8 support is mandatory for java
            }
        }
        last = next + 1;
    }
    return result;
}
person Oliv    schedule 12.01.2017

Основываясь на ответе @anon01, вот как это сделать в Groovy:

Map<String,String> getQueryParameters( HttpExchange httpExchange )
{
    def query = httpExchange.getRequestURI().getQuery()
    return query.split( '&' )
            .collectEntries {
        String[] pair = it.split( '=' )
        if (pair.length > 1)
        {
            return [(pair[0]): pair[1]]
        }
        else
        {
            return [(pair[0]): ""]
        }
    }
}

И вот как это использовать:

def queryParameters = getQueryParameters( httpExchange )
def parameterA = queryParameters['A']
person Wim Deblauwe    schedule 31.08.2015
comment
Что ж, спасибо тебе. Но вопрос касается Java, а не Groovy;) - person Tibor; 01.09.2015

Наткнулся на это и решил, что я бы бросил Java 8/Streams здесь, добавив несколько дополнительных битов (не в предыдущих ответах).

Дополнительно 1: я добавил фильтр, чтобы избежать обработки любых пустых параметров. Что-то, чего не должно происходить, но это позволяет более чистую реализацию по сравнению с тем, чтобы не обрабатывать проблему (и отправлять пустой ответ). Пример этого будет выглядеть так ?param1=value1&param2=

Дополнительно 2: я использовал String.split(String regex, int limit) для второй операции разделения. Это позволяет передавать такой параметр запроса, как ?param1=it_has=in-it&other=something.

public static Map<String, String> getParamMap(String query) {
    // query is null if not provided (e.g. localhost/path )
    // query is empty if '?' is supplied (e.g. localhost/path? )
    if (query == null || query.isEmpty()) return Collections.emptyMap();

    return Stream.of(query.split("&"))
            .filter(s -> !s.isEmpty())
            .map(kv -> kv.split("=", 2)) 
            .collect(Collectors.toMap(x -> x[0], x-> x[1]));

}

Импорт

import java.util.Map;
import java.util.Collections;
import java.util.stream.Stream;
import java.util.stream.Collectors;
person Brian    schedule 20.09.2020