【问题标题】:Grabbing the range values from the HttpHeader从 HttpHeader 中获取范围值
【发布时间】:2012-01-12 19:54:29
【问题描述】:

出于分页的目的,我们的 UI 人员在 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,所以我很可能以错误的方式思考这个问题。

是否有替代正则表达式的方法来从 SpringMVC 中的 http 标头解析此类范围信息?

【问题讨论】:

    标签: java spring-mvc solr pagination range


    【解决方案1】:

    符合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;
        }
    };
    

    或看看here

    【讨论】:

      【解决方案2】:

      这是从服务器以分块方式请求数据的最佳方式吗?

      另一种方法是使用请求参数:

      /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]);
      

      【讨论】:

        【解决方案3】:

        如果目标类型不是字符串,@RequestParameter 和 @RequestHeader 参数都会进行类型转换。如果您有 Range 类型,则可以创建一个 Converter 并将其注册到 conversionService。然后你的控制器会看起来更干净一些:

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

        如果它经常出现在控制器中,这将很有用。或者,如果只是在控制器方法中进行解析的一个地方就足够了。

        【讨论】:

          猜你喜欢
          • 2021-09-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多