java - JAX-RS/Jersey如何自定義錯誤處理?




rest error-handling (6)

我正在使用Jersey學習JAX-RS(aka,JSR-311)。 我成功地創建了一個根資源,並且正在使用參數:

@Path("/hello")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public String get(
        @QueryParam("name") String name,
        @QueryParam("birthDate") Date birthDate) {

         // Return a greeting with the name and age
    }
}

這很好用,並處理Date(String)構造函數可以理解的當前語言環境中的任何格式(如YYYY / mm / dd和mm / dd / YYYY)。 但是如果我提供一個無效或不明白的值,我會得到一個404響應。

例如:

GET /hello?name=Mark&birthDate=X

404 Not Found

我如何定制這種行為? 也許是不同的響應代碼(可能是“400錯誤請求”)? 如何記錄錯誤? 也許在自定義標題中添加問題描述(“錯誤的日期格式”)以幫助解決問題? 或者返回一個包含詳細信息的錯誤響應,以及一個5xx狀態碼?


@QueryParam文檔說

“註釋參數,字段或屬性的類型T必須是:

1)是一個原始類型
2)有一個接受單個String參數的構造函數
3)有一個名為valueOf或fromString的靜態方法,它接受一個String參數(例如,參見Integer.valueOf(String))
4)有一個javax.ws.rs.ext.ParamConverterProvider JAX-RS擴展SPI的註冊實現,它返回一個javax.ws.rs.ext.ParamConverter實例,該實例能夠為該類型進行“字符串”轉換。
5)是List,Set或SortedSet,其中T滿足上述2,3或4。 結果集合是只讀的。 “

如果您想要控制在String形式的查詢參數無法轉換為您的類型T時發送給用戶的響應,則可以拋出WebApplicationException。 Dropwizard附帶以下*參數類,您可以使用您的需求。

BooleanParam,DateTimeParam,IntParam,LongParam,LocalDateParam,NonEmptyStringParam,UUIDParam。 見https://github.com/dropwizard/dropwizard/tree/master/dropwizard-jersey/src/main/java/io/dropwizard/jersey/params

如果您需要Joda DateTime,只需使用Dropwizard github.com/dropwizard/dropwizard/blob/master/dropwizard-jersey/…

如果以上列表不適合您的需求,請通過擴展AbstractParam來定義您自己的需求。 覆蓋解析方法。 如果您需要控制錯誤響應正文,請覆蓋錯誤方法。

來自Coda Hale的好文章在http://codahale.com/what-makes-jersey-interesting-parameter-classes/

import io.dropwizard.jersey.params.AbstractParam;

import java.util.Date;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

public class DateParam extends AbstractParam<Date> {

    public DateParam(String input) {
        super(input);
    }

    @Override
    protected Date parse(String input) throws Exception {
        return new Date(input);
    }

    @Override
    protected Response error(String input, Exception e) {
        // customize response body if you like here by specifying entity
        return Response.status(Status.BAD_REQUEST).build();
    }
}

Date(String arg)構造函數已棄用。 如果您使用Java 8,我會使用Java 8日期類。否則建議使用joda日期時間。


一個明顯的解決方案:接受一個字符串,自己轉換為Date。 這樣你就可以定義你想要的格式,捕獲異常並重新拋出或自定義發送的錯誤。 為了解析,SimpleDateFormat應該可以正常工作。

我確信也有辦法為數據類型掛接處理程序,但在這種情況下,可能只需要一點簡單的代碼即可。


如果Jersey無法解組參數,Jersey會拋出com.sun.jersey.api.ParamException,因此一種解決方案是創建一個處理這些類型異常的ExceptionMapper:

@Provider
public class ParamExceptionMapper implements ExceptionMapper<ParamException> {
    @Override
    public Response toResponse(ParamException exception) {
        return Response.status(Status.BAD_REQUEST).entity(exception.getParameterName() + " incorrect type").build();
    }
}

我也很喜歡StaxMan可能會將該QueryParam實現為一個String,然後處理轉換,必要時重新拋出。

如果特定於語言環境的行為是期望和預期的行為,則可以使用以下內容返回400 BAD REQUEST錯誤:

throw new WebApplicationException(Response.Status.BAD_REQUEST);

有關更多選項,請參閱JavaDoc for javax.ws.rs.core.Response.Status


這實際上是正確的行為。 澤西將嘗試為您的輸入找到一個處理程序,並嘗試從提供的輸入中構建一個對象。 在這種情況下,它將嘗試使用提供給構造函數的值X創建一個新的Date對象。 由於這是一個無效的日期,所以約定澤西島將返回404。

你可以做的是重寫並把出生日期作為一個字符串,然後嘗試解析,如果你沒有得到你想要的,你可以自由地拋出任何異常映射機制所需的異常(有幾個)。


@Provider
public class BadURIExceptionMapper implements ExceptionMapper<NotFoundException> {

public Response toResponse(NotFoundException exception){

    return Response.status(Response.Status.NOT_FOUND).
    entity(new ErrorResponse(exception.getClass().toString(),
                exception.getMessage()) ).
    build();
}
}

創建上面的類。 這將處理404(NotFoundException),並且在toResponse方法中,您可以提供自定義響應。 同樣,還有ParamException等,您需要映射以提供自定義響應。





jax-rs