2011-06-29 36 views
15

Với dịch vụ JAX-RS rất đơn giản của tôi, tôi đang sử dụng Tomcat với lĩnh vực JDBC để xác thực, do đó tôi đang làm việc với các chú thích JSR 250.Phản hồi trạng thái HTTP tùy chỉnh với JAX-RS (Jersey) và @RolesAllowed

Vấn đề là tôi muốn trả về phần thân thư tùy chỉnh trong phản hồi trạng thái HTTP. Mã trạng thái (403) nên giữ nguyên. Ví dụ, dịch vụ của tôi trông giống như sau:

@RolesAllowed({ "ADMIN" }) 
@Path("/users") 
public class UsersService { 

    @GET 
    @Produces(MediaType.TEXT_PLAIN) 
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) 
    public String getUsers() { 
     // get users ... 
     return ...; 
    } 
} 

Nếu một người dùng với một vai trò khác với "ADMIN" truy cập vào dịch vụ, tôi muốn thay đổi thông điệp trả lời cho một cái gì đó như thế (tùy thuộc vào loại phương tiện truyền thông [ xml/json]):

<error id="100"> 
    <message>Not allowed.</message> 
</error> 

Tại thời điểm Jersey trả về cơ thể sau đây:

HTTP Status 403 - Forbidden 

type Status report 
message Forbidden 
description Access to the specified resource (Forbidden) has been forbidden. 
Apache Tomcat/7.0.12 

Làm thế nào tôi có thể thay đổi nội dung thư mặc định? Có cách nào để xử lý ngoại lệ (có thể bị ném) để xây dựng phản hồi trạng thái HTTP của riêng tôi không?

+0

Ví dụ hoàn chỉnh: https://www.bhaveshthaker.com/25/customize-handling-server-side-exceptions-with-error-codes-using-exceptionmapper-with-jersey-jax-rs-in-java/ – RAS

Trả lời

17

Cách dễ nhất để xử lý loại sự việc này là ném ngoại lệ và đăng ký một người lập bản đồ ngoại lệ để chuyển đổi thành loại thư bạn muốn gửi trong trường hợp đó. Vì vậy, giả sử bạn ném một AccessDeniedException, sau đó bạn sẽ có một bộ xử lý như thế này (với tên lớp đầy đủ ở những nơi cho rõ ràng):

@javax.ws.rs.ext.Provider 
public class AccessDeniedHandler 
     implements javax.ws.rs.ext.ExceptionMapper<AccessDeniedException> { 
    public javax.ws.rs.core.Response toResponse(AccessDeniedException exn) { 
     // Construct+return the response here... 
     return Response.status(403).type("text/plain") 
       .entity("get lost, loser!").build(); 
    } 
} 

Cách thức mà bạn đăng ký mapper ngoại lệ thay đổi tùy theo khuôn khổ bạn' tái sử dụng, nhưng đối với Jersey bạn nên sử dụng chỉ với @Provider. Tôi sẽ cho phép bạn tìm ra chính mình cách bạn muốn tạo loại tài liệu lỗi mà bạn muốn, nhưng tôi khuyên bạn nên xử lý lỗi dưới dạng mã lỗi HTTP của một số loại (đó là RESTful ...)

+0

Điều này là Jersey trả về phản hồi 403 tùy chỉnh của nó. Tôi không thể ném 'AccessDeniedException' cho ủy quyền vì công cụ @RolesAllowed xử lý việc này. Mã lỗi HTTP phải là một số tôi chỉ muốn thay đổi thông báo nội dung. – Stefan

+0

Tôi nghĩ bạn có thể làm điều đó ở Jersey với một ExceptionMapper; Tôi biết bạn có thể với Apache CXF (mặc dù nó được cấu hình khác nhau vì lý do tôi đã đánh giá cao) vì vậy tôi tin rằng nó hợp lý để ít nhất _try_ cho rằng họ đều là động cơ JAX-RS và điều này chỉ sử dụng API JAX-RS , nhưng tôi không có kinh nghiệm trực tiếp với Jersey vì vậy có thể có điều gì đó bất ngờ trong cách này. –

9

Với việc tạo một ExceptionMapper (ngoại lệ bản đồ của WebApplicationException) người ta có thể "bắt" ngoại lệ nhất định ném bởi ứng dụng:

@Provider 
public class MyExceptionMapper implements ExceptionMapper<WebApplicationException> { 

    @Override 
    public Response toResponse(WebApplicationException weException) { 

     // get initial response 
     Response response = weException.getResponse(); 

     // create custom error 
     MyError error = ...; 

     // return the custom error 
     return Response.status(response.getStatus()).entity(error).build(); 
    } 
} 

bạn cũng cần phải thêm gói để web.xml đơn xin đăng ký nhà cung cấp:

<init-param> 
    <param-name>com.sun.jersey.config.property.packages</param-name> 
    <param-value> 
     com.myapp.userservice; // semi-colon seperated 
     com.myapp.mappedexception 
    </param-value> 
</init-param> 
+0

Tôi đã đối mặt với cùng một vấn đề và trong trường hợp của tôi đó là câu trả lời hoàn hảo. Cảm ơn Stefan! – Lars

1

REST được xây dựng dựa trên HTTP nên bạn không phải thay đổi hành vi mặc định của lỗi xác thực. Có một lỗi 403 khi truy cập vào một tài nguyên là đủ cho khách hàng để hiểu rõ ràng những gì gắn thêm.

Càng nhiều tài nguyên của bạn tuân thủ HTTP, càng có nhiều tài nguyên khác có thể hiểu được.

+2

vấn đề là có thể có nhiều tình huống khác nhau một http lỗi duy nhất.Một có thể là một phiên thời gian ra (kết quả trong 403) được quản lý bởi AS. Người khác có thể là một người thừa kế trái phép đối với tài nguyên còn lại (403). Nếu bạn phải lập trình phản ứng theo những cách khác nhau về những lỗi đó, đó là cách tốt để tùy chỉnh chúng. – Lars

Các vấn đề liên quan