2012-12-04 22 views
6

Chúng tôi đang sử dụng Dropwizard/Jersey để xây dựng một dịch vụ web. Tài nguyên có đường dẫn và phương thức có đường dẫn con. Khi trả về được tạo (201), đường dẫn của phương thức mà chúng tôi đang nhận được được thêm vào vị trí chúng tôi cung cấp. Khi trở về trạng thái OK với một vị trí (contrived tôi biết), tất cả là tốt, và vị trí được trả lại giống như chúng tôi cung cấp nó.Đường dẫn phương thức trả trước Javax khi thiết lập đường dẫn tiêu đề Vị trí trên Trạng thái Đã tạo

Làm cách nào chúng tôi có thể trả lại vị trí không phải là đường dẫn con của vị trí của phương pháp của chúng tôi?

Trong ví dụ bên dưới: lệnh nhận "http: // localhost/foo/bar" (trạng thái đã tạo) phản hồi vị trí "http: // localhost/foo/bar/wibble" (lưu ý /foo/bar)

trong khi truy cập "http: // localhost/foo/baz" (trạng thái ok) phản hồi vị trí của "http: // localhost/wibble", đó là những gì chúng tôi muốn.

import javax.ws.rs.POST; 
import javax.ws.rs.Path; 
import javax.ws.rs.core.Response; 
import java.net.URI; 

@Path("/foo") 
public class FooResource { 

    @POST 
    @Path("/bar") 
    public Response bar() { 

     URI uriOfCreatedResource = URI.create("/wibble"); 
     return Response.created(uriOfCreatedResource).build(); 
    } 

    @POST 
    @Path("/baz") 
    public Response baz() { 

     URI uriOfCreatedResource = URI.create("/wibble"); 
     return Response.ok().location(uriOfCreatedResource).build(); 
    } 
} 

Trả lời

4

Đã xảy ra với tôi trên GlassFish (JavaEE6). Tôi nghĩ rằng đó là một lỗi, nhưng tôi không bao giờ quản lý để đào mã để chuyển đổi URI thực tế ....

Tôi đã tìm thấy một workaround mặc dù:

public Response bar(@Context UriInfo info) { 
    URI absoluteURI=info.getBaseUriBuilder().path("/wibble").build(); 
    return Response.created(absoluteURI).build(); 
} 
+0

Cảm ơn, tôi sẽ thử điều đó. Cách giải quyết hiện tại của chúng tôi là trả lại trạng thái 200 bằng URL trong một đối tượng, được gửi theo thứ tự đến JSON. –

7

Trong trường hợp ai đó tình cờ ở đây thắc mắc về điều này; Tôi đào sâu vào mã của Jersey để xem tại sao điều này lại xảy ra. Điều này sẽ giải thích vấn đề của bạn & Cách giải quyết của Carlo.

com.sun.jersey.spi.container.ContainerResponse chứa đá quý này:

private void setHeaders(MultivaluedMap<String, Object> headers) { 
    this.headers = headers; 
    Object location = headers.getFirst(HttpHeaders.LOCATION); 
    if (location != null) { 
     if (location instanceof URI) { 
      final URI locationUri = (URI)location; 
      if (!locationUri.isAbsolute()) { 
       final URI base = (statusType.getStatusCode() == Status.CREATED.getStatusCode()) 
         ? request.getAbsolutePath() // WHY!? 
         : request.getBaseUri(); 
       location = UriBuilder.fromUri(base). 
         path(locationUri.getRawPath()). 
         replaceQuery(locationUri.getRawQuery()). 
         fragment(locationUri.getRawFragment()). 
         build(); 
      } 
      headers.putSingle(HttpHeaders.LOCATION, location); 
     } 
    } 
} 

Nói cách khác: đối với một số lý do, ai đó quyết định đó là một ý tưởng tốt để điều trị tiêu đề vị trí khác nhau nếu các phản ứng mã trạng thái là 201. Giống như Carlo nhận thấy, sử dụng đường dẫn tuyệt đối tránh được vấn đề này.

+0

Thật tuyệt vời! Cảm ơn vì công việc thám tử tốt đẹp - là "TẠI SAO" bình luận của bạn, hay trong nguồn gốc? (ví dụ, ngay cả các nhà phát triển Jersey nghĩ rằng điều này là kỳ lạ?) –

+1

Tôi đã thêm WHY để nhấn mạnh, tôi cần phải rõ ràng hơn về điều đó :) – henriks

+0

Có thể vì đặc điểm kỹ thuật (http://www.w3.org/Protocols) /rfc2616/rfc2616-sec10.html#sec10.2.2) nói "với URI cụ thể nhất cho tài nguyên được cung cấp bởi trường tiêu đề Vị trí" .. – Jonas

0

Trong Jersey 2.x mã có liên quan đã được viết lại hoàn toàn và di chuyển đến địa điểm khác. Bên trong lớp org.glassfish.jersey.server.ServerRuntime, các phương pháp sau đây được gọi là thời gian ghi dữ liệu đáp ứng:

private static void ensureAbsolute(final URI location, final MultivaluedMap<String, Object> headers, 
             final ContainerRequest request) { 
     if (location == null || location.isAbsolute()) { 
      return; 
     } 
     // according to RFC2616 (HTTP/1.1), this field can contain one single URI 
     headers.putSingle(HttpHeaders.LOCATION, request.getBaseUri().resolve(location)); 
    } 

Như đã nói ở trên, trừ việc áp dụng bộ một URI tuyệt đối (một URI mà bắt đầu với một sơ đồ như http: hoặc ftp:) cho tiêu đề Địa , Jersey tự động thêm vào nó với URI cơ bản của yêu cầu.

Thật lạ là Jersey không cho phép kiểm soát hoặc vô hiệu hóa hành vi này.