這是本文件的舊版!
How to fetch raw message after the request is failed? (working)
Problem
RESTEasy jackson provider讓我們可以輕鬆的將第三方服務回應的json內容,轉成我們自己的物件,讓程式碼只專注於資源物件的操作;然而,第三方服務並非永遠都如你預期,它可能突然更新甚至吐出你不認得的訊息:
javax.ws.rs.ProcessingException: RESTEASY003145: Unable to find a MessageBodyReader of content-type text/html;charset=iso-8859-1我有幸遇到這樣的問題,也讓我思考著該如何將原始資料記錄下來以回報第三方服務提供者。本篇文章分享可能的作法,可依照你的需求自行挑選。
How to resolve?
ReadInterceptor & InputStreamSniffer
一開始遇到這個問題時,我的想法是: 是否可以透過interceptor去處理? 我所提供的第一個方法,是註冊一個ReadInterceptor,並且wrap原始的InputStream,將讀取的內容給記錄下來。首先是ReaderInterceptor,它會從Context中取出InputStream,並將其wrap成InputStreamSniffer,代整個讀取流程執行後,可以透過getReadContent去拿到讀取的內容:
@Provider public class SnifferReadInterceptor implements ReaderInterceptor { private InputStreamSniffer inputStreamSniffer = null; @Override public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException { InputStream inputStream = context.getInputStream(); inputStreamSniffer = new InputStreamSniffer(inputStream); context.setInputStream(inputStreamSniffer); return context.proceed(); } public String getReadContent(){ return inputStreamSniffer.getContent(); } }InputStreamSniffer則是將讀取的動作delegate給原始的InputStream,並悄悄地記下讀取內容:
public class InputStreamSniffer extends InputStream { private InputStream srcInputStream; private StringBuilder contentStringBuilder; public InputStreamSniffer(InputStream inputStream){ srcInputStream = inputStream; contentStringBuilder = new StringBuilder(); } @Override public int read() throws IOException { int read_c = srcInputStream.read(); contentStringBuilder.append((char)read_c); return read_c; } // .. skip我簡單的寫了一個測試,想要確認將message轉為json物件發生問題時,readInterceptor是否可以拿到message:
@Test public void testSnifferReadInterceptorWithReadFailed(){ Invocation invocation = initInvocation(); Response response = null; try { response = invocation.invoke(); response.readEntity(TestModel.class); fail("should be failed "); } catch( ProcessingException e ) { // Can't find valid messageBodyReader assertTrue(readInterceptor.getReadContent().isEmpty()); } finally { response.close(); } }答案是不行的,這是由於RESTEasy。