Các đọc các thông tin trong HTTP Header với Spring Rest

Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu cách đọc các thông tin trong HTTP header với Spring Rest.

Đầu tiên chúng ta sẽ sử dụng @RequestHeader annotation để đọc một thông tin cụ thể trong HTTP header. Ngoài ra @RequestHeader còn cho phép chúng ta đọc hết tất cả những thông tin trong HTTP header cùng một lần thông qua việc sử dụng Map.

Truy cập các thông tin trong HTTP header

Thuộc tính cụ thể

Nếu nhu cầu chỉ cần đọc một thông tin cụ thể nào đó trong HTTP header thì chúng ta có thể sử dụng @RequestHeader với tên của thuộc tính mà chúng ta cần đọc.

@GetMapping("/greeting")
public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {
    // code here
}

Bằng cách khai báo như trên thì chúng ta đã có thể đọc được thông tin về accept-language trong HTTP header. Nếu thông tin này không được tìm thấy trong request thì method này sẽ trả về lỗi “400 Bad Request”.

Lưu ý rằng @RequestHeader sẽ giúp chúng ta chuyển đổi dữ liệu sang kiểu dữ liệu tương ứng chứ không nhất thiết phải là String. Giả sử có một thông tin my-number trong HTTP header dạng số nguyên thì chúng ta hoàn toàn có thể sử dụng như sau:

@GetMapping("/double")
public ResponseEntity<String> doubleNumber(@RequestHeader("my-number") int myNumber) {
    return new ResponseEntity<String>(String.format("%d * 2 = %d", 
      myNumber, (myNumber * 2)), HttpStatus.OK);
}

Toàn bộ thông tin

Ngoài việc cho phép truy cập một thông tin cụ thể trong HTTP header thì chúng ta còn có thể sử dụng @RequestHeader để lấy toàn bộ thông tin trong đó thông qua Map. 

@GetMapping("/listHeaders")
public ResponseEntity<String> listAllHeaders(
  @RequestHeader Map<String, String> headers) {
    headers.forEach((key, value) -> {
        LOG.info(String.format("Header '%s' = %s", key, value));
    });

    return new ResponseEntity<String>(
      String.format("Listed %d headers", headers.size()), HttpStatus.OK);
}

Nếu chúng ta sử dụng Map và một trong các HTTP header có nhiều hơn một giá trị, chúng ta sẽ chỉ nhận được giá trị đầu tiên.

Nếu có một HTTP header nào đó chứa nhiều hơn một giá trị thì chúng ta có thể sử dụng MultiValueMap để lấy tất cả những giá trị này.

@GetMapping("/multiValue")
public ResponseEntity<String> multiValue(
  @RequestHeader MultiValueMap<String, String> headers) {
    headers.forEach((key, value) -> {
        LOG.info(String.format(
          "Header '%s' = %s", key, value.stream().collect(Collectors.joining("|"))));
    });
        
    return new ResponseEntity<String>(
      String.format("Listed %d headers", headers.size()), HttpStatus.OK);
}

Ngoài ra chúng ta cũng có thể sử dụng HTTPHeader class để có được kết quả tương tự như trên.

@GetMapping("/getBaseUrl")
public ResponseEntity<String> getBaseUrl(@RequestHeader HttpHeaders headers) {
    InetSocketAddress host = headers.getHost();
    String url = "http://" + host.getHostName() + ":" + host.getPort();
    return new ResponseEntity<String>(String.format("Base URL = %s", url), HttpStatus.OK);
}

Các thuộc tính trong @RequestHeader annotation

Sau khi chúng ta đã biết các cách sử dụng @RequestHeader annotation cơ bản thì trong phần này chúng ta sẽ cùng phân tích kỹ hơn các thuộc tính mà nó cung cấp.

Trong các ví dụ trên chúng ta đang ngầm sử dụng thuộc tính namevalue trong @RequestHeader.

Ví dụ dưới đây sẽ chỉ ra rằng 3 cách sử dụng đều cho kết quả như sau

public ResponseEntity<String> greeting(@RequestHeader("accept-language") String language) {}

Hay

public ResponseEntity<String> greeting(
  @RequestHeader(name = "accept-language") String language) {}


Hay

public ResponseEntity<String> greeting(
  @RequestHeader(value = "accept-language") String language) {}

Một điểm lưu ý rằng khi chúng ta chỉ định tên của header thông qua một trong 3 cách trên thì mặc định thuộc tính này bắt buộc phải có trong HTTP header nếu không nó sẽ trả về lỗi 400.

Chúng ta có thể bỏ qua lỗi này bằng cách sử dụng thuộc tính required cho phép controller có thể sử dụng tiếp ngay cả khi không có một giá trị cho một thuộc tính đã được chỉ định sẵn. Nhưng hãy lưu ý kiểm tra dữ liệu trước khi sử dụng vì nó có thể gây ra NullPointerException khi dữ liệu bị null.

@GetMapping("/nonRequiredHeader")
public ResponseEntity<String> evaluateNonRequiredHeader(
  @RequestHeader(value = "optional-header", required = false) String optionalHeader) {
    return new ResponseEntity<String>(String.format(
      "Was the optional header present? %s!",
        (optionalHeader == null ? "No" : "Yes")),HttpStatus.OK);
}

Có một cách khác để tránh việc chúng ta bị NullPointerException hay cần phải viết thêm code để kiểm tra dữ liệu bằng thuộc tính defaultValue cho phép đặt giá trị mặc định trong trường hợp thông tin được chỉ định bị thiếu trong HTTP header.

@GetMapping("/default")
public ResponseEntity<String> evaluateDefaultHeaderValue(
  @RequestHeader(value = "optional-header", defaultValue = "3600") int optionalHeader) {
    return new ResponseEntity<String>(
      String.format("Optional Header is %d", optionalHeader), HttpStatus.OK);
}

Tóm lược

@RequestHeader annotation là công cụ tuyệt vời để chúng ta có thể đọc các thông tin trong HTTP header một cách dễ dàng. Ngoài ra việc kết hợp sử dụng các thuộc tính được @RequestHeader annotation cung cấp có thể giúp chúng ta giảm khả năng gây lỗi.

Nguồn

https://www.baeldung.com/spring-rest-http-headers

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x