Получение значений диапазона из HttpHeader

Для целей нумерации страниц наш парень с пользовательским интерфейсом указывает диапазоны элементов в заголовке Http следующим образом:

Range: items=0-15

В последующих запросах диапазоны из Интернета могут быть либо

Range: items=16-31
Range: items=32-45

...и т.д...и т.д.

В моем контроллере SearchRequestController.java я пытаюсь извлечь эти диапазоны, чтобы я мог отправить их на сервер Solr, чтобы вернуть значения в запрошенных патронах, установив начало и смещение.

Я делаю следующее (в SearchRequestController.java):

@RequestMapping("/billsSearch")
@ResponseBody
public SearchResult searchBills(HttpServletRequest request,@RequestBody SearchRequest searchRequest){
    String rangeRequest = request.getHeader("Range");
    //(1)Parse the rangeRequest using some mechanism
    //(2)Set the start using the first value of the range
    //(3) Add the second value to the start to get the offset
    searchRequest.setStart(startValue);
    searchRequest.setOffset(offsetValue);
    return searchHelper(request,searchRequest);
}

У меня есть пара вопросов: Это лучший способ запрашивать данные с сервера по частям?

Как извлечь диапазоны из заголовка запроса?

Я предполагаю, что request.getHeader("Range") вернет "items=16-31".

Является ли регулярное выражение лучшим способом получить 16 и 31 из этой строки?

Если я решу использовать регулярное выражение, не сломается ли выражение, если я изменю заголовок диапазона на billItems=16-31?

Я регулярное выражение n00b, поэтому вполне возможно, что я неправильно об этом думаю.

Есть ли альтернативы регулярному выражению для анализа информации о диапазоне, подобной этой, из заголовков http в SpringMVC?


person sc_ray    schedule 12.01.2012    source источник


Ответы (3)


Это лучший способ запросить данные с сервера по частям?

Другой подход заключается в использовании параметров запроса:

/billsSearch?from=15&to=31

Кстати, вы можете использовать @RequestHeader аннотация:

public SearchResult searchBills(
        @RequestBody SearchRequest searchRequest,
        @RequestHeader("Range") String range) {
    //...
}

Как извлечь диапазоны из заголовка запроса? [...] Является ли регулярное выражение лучшим способом получить 16 и 31 из этой строки?

Я бы вырезал завершающую строку "items=", разделил бы на символ - и проанализировал два полученных числа:

String[] ranges = range.substring("items=".length()).split("-");
int from = Integer.valueOf(ranges[0]);
int to = Integer.valueOf(ranges[1]);
person Tomasz Nurkiewicz    schedule 12.01.2012

Простой анализатор заголовков диапазона, соответствующий http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35

class Range {
    Integer start;
    Integer end;
    Integer suffixLength;
}

public class Main {

    public static void main(String[] args) {
        String input = "bytes=33-22,-333,20-,-55,43-0002";
        for (Range range : decodeRange(input)) {
            if (range.suffixLength == null) {
                System.out.printf("Range: %d->%s\n", range.start, range.end == null ? "enf of file" : range.end);
            } else {
                System.out.printf("Last %d bytes\n", range.suffixLength);
            }
        }
    }

    public static List<Range> decodeRange(String rangeHeader) {
        List<Range> ranges = new ArrayList<>();
        String byteRangeSetRegex = "(((?<byteRangeSpec>(?<firstBytePos>\\d+)-(?<lastBytePos>\\d+)?)|(?<suffixByteRangeSpec>-(?<suffixLength>\\d+)))(,|$))";
        String byteRangesSpecifierRegex = "bytes=(?<byteRangeSet>" + byteRangeSetRegex + "{1,})";
        Pattern byteRangeSetPattern = Pattern.compile(byteRangeSetRegex);
        Pattern byteRangesSpecifierPattern = Pattern.compile(byteRangesSpecifierRegex);
        Matcher byteRangesSpecifierMatcher = byteRangesSpecifierPattern.matcher(rangeHeader);
        if (byteRangesSpecifierMatcher.matches()) {
            String byteRangeSet = byteRangesSpecifierMatcher.group("byteRangeSet");
            Matcher byteRangeSetMatcher = byteRangeSetPattern.matcher(byteRangeSet);
            while (byteRangeSetMatcher.find()) {
                Range range = new Range();
                if (byteRangeSetMatcher.group("byteRangeSpec") != null) {
                    String start = byteRangeSetMatcher.group("firstBytePos");
                    String end = byteRangeSetMatcher.group("lastBytePos");
                    range.start = Integer.valueOf(start);
                    range.end = end == null ? null : Integer.valueOf(end);
                } else if (byteRangeSetMatcher.group("suffixByteRangeSpec") != null) {
                    range.suffixLength = Integer.valueOf(byteRangeSetMatcher.group("suffixLength"));
                } else {
                    throw new RuntimeException("Invalid range header");
                }
                ranges.add(range);
            }
        } else {
            throw new RuntimeException("Invalid range header");
        }
        return ranges;
    }
};

или посмотрите здесь

person gliviu    schedule 01.10.2015

Оба аргумента @RequestParameter и @RequestHeader подлежат преобразованию типа, если целевой тип не является строкой. Если бы у вас был тип Range, вы могли бы создать Converter‹String, Range› и зарегистрировать его в convertService. Тогда ваш контроллер будет выглядеть немного чище:

    public SearchResult searchBills(
            @RequestBody SearchRequest searchRequest,
            @RequestHeader Range range) {
        //...
    }

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

person Rossen Stoyanchev    schedule 13.01.2012