2017-05-02 6 views
2

나는 GWT의 RPC에서 매개 변수가 ClientSerializationStreamWriter를 사용하여 클라이언트에서 직렬화되고 ServerSerializationStreamReader를 사용하여 서버에서 직렬화 해제되고 다른 한편으로는 반환 값이 ServerSerializationStreamWriter를 사용하여 서버에서 직렬화되고 클라이언트를 사용하여 클라이언트에서 역 직렬화됨을 이해했습니다. ClientserializationStreamReader.GWT의 RPC 직렬화 메커니즘을 확장하는 방법은 무엇입니까?

나는 serialize 된 매개 변수 (client-> server) 또는 반환 값 (server-> client)을 기반으로 체크섬이나 유사한 것을 계산하여 직렬화 스트림에 추가하려고합니다. 수신 측에서 체크섬은 일련 화되고 수신 된 매개 변수 또는 반환 값 (물론 추가 체크섬없이)에서 다시 계산되고 수신 된 체크섬과 비교됩니다.

체크섬 계산을 구체적인 매개 변수/반환 값 유형과 독립적으로 유지하려면 원본 유형 대신 직렬화 된 값을 기반으로 계산하는 것이 좋습니다. 이것은 객체 그래프의 추가적인 트래버스를 없애고 또 다른 문제를 해결할 수 있습니다 : 자바의 리플렉션 API (클라이언트에서는 사용할 수 없음)에 의존하지 않고 객체 그래프의 모든 값을 고려합니다.

먼저 매개 변수 개체 (지정된 RPC의 실제 매개 변수로 구성됨)와 반환 값 래퍼를 소개 한 다음 사용자 지정 필드 serializer를 소개했습니다. 직렬화에서 먼저 매개 변수/반환 값을 직렬화하고 * SerializationStreamWriter에서 직렬화 된 값에 액세스하고 체크섬을 계산하고 같은 * SerializationStreamReader를 사용하여 체크섬을 작성할 수 있습니다. 그러나 수신기의 끝에 그것은 첫 번째 사용자 지정 필드 serializer가 호출 될 때 serialization 스트림이 이미 토큰 화되어 있으므로 실제로 * SerializationStreamReader를 사용하지 않고 serialize 된 값에 액세스 할 수없는 것 같습니다.

그래서 질문은 :

  1. 내가보고 싶었어요 후크가? 또는
  2. 같은 방법 (동일한 형식)으로 클라이언트와 서버에서 객체 그래프를 직렬화하고 구체적인 매개 변수 또는 반환 값 유형에 특정한 것을 구현할 필요가없는 효율적인 방법이 있습니까?
+0

방법 서버 측에 서블릿 필터를 사용하고 사용자 정의 ['RpcRequestBuilder'] (약 http://www.gwtproject.org/javadoc/latest/com : GWT의 RPCServletUtils는 몇 가지 유용한 방법의 herefore있다 /google/gwt/user/client/rpc/RpcRequestBuilder.html)? –

답변

0

사실 토마스 (질문에 덧붙음 참조)가 질문에 대답했습니다. @ 토마스 : 고마워. 이전 연구에서 내가 놓쳤던 바로 그 것이었다.

몇 가지 세부 정보를 추가 할 수 있습니다.

IMyServiceAsync service = GWT.create(IMyService.class); 
((ServiceDefTarget)service).setRpcRequestBuilder(new MyCustomRpcRequestBuilder()); 

이 약 요청을 조작 할 수 doSetRequestData를 오버라이드 (override) 할 필요가 RpcRequestBuilder 사용자 정의가 전송 될 : 클라이언트 측에서, 토마스 비동기 서비스 인터페이스에 설정해야합니다 RpcRequestBuilder 사용자 지정 제안으로

이 처리되기 전에 doSetCallback는 그 응답에 손을 얻을 : 서블릿 필터가 사용될 수있는 서버 측

private final class MyCustomRpcRequestBuilder extends RpcRequestBuilder { 
    @Override 
    protected void doSetRequestData(RequestBuilder rb, String payload) { 
    // do whatever you need to do on the payload, request header, ... 
    String checksum = calculateChecksum(payload); 
    rb.setHeader(MY_CUSTOM_HEADER_NAME, checksum); 
    super.doSetRequestData(rb, payload); 
    } 

    @Override 
    protected void doSetCallback(RequestBuilder rb, final RequestCallback callback) { 
    super.doSetCallback(rb, new RequestCallback() { 
     @Override 
     public void onResponseReceived(Request request, Response response) { 
     // do whatever you need to do on the response header, ... 
     String receivedChecksum = response.getHeader(MY_CUSTOM_HEADER_NAME); 
     if (receivedChecksum.equals(calculateChecksum(response.getText())) { 
      callback.onResponseReceived(request, response); 
     } 
     else { 
      callback.onError(request, new InvalidChecksumException(...)); 
     } 
     } 

     @Override 
     public void onError(Request request, Throwable exception) { 
     callback.onError(request, exception); 
     } 
    }); 
    } 
} 

한다.

public class MyFilter implements Filter { 
    @Override 
    public void init(FilterConfig filterConfig) throws ServletException { 
    } 

    @Override 
    public void destroy() { 
    } 

    @Override 
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException { 
    HttpServletRequest httpReq = (HttpServletRequest)req; 
    HttpServletResponse httpResp = (HttpServletResponse)resp; 

    String receivedChecksum = httpReq.getHeader(MY_CUSTOM_HEADER_NAME); 
    String reqPayload = RPCServletUtils.readContentAsGwtRpc(httpReq); 
    if (receivedChecksum.equals(calculateChecksum(reqPayload)) { 
     final ServletInputStream inputStream = new ByteArrayServletInputStream(reqPayload.getBytes(RPCServletUtils.CHARSET_UTF8)); 
     HttpServletRequestWrapper reqWrapper = new HttpServletRequestWrapper(httpReq) { 
     @Override 
     public ServletInputStream getInputStream() throws IOException { 
      return inputStream; 
     } 
     }; 
     final CachingServletOutputStream outputStream = new CachingServletOutputStream(); 
     HttpServletResponseWrapper respWrapper = new HttpServletResponseWrapper(httpResp) { 
     @Override 
     public ServletOutputStream getOutputStream() throws IOException { 
      return outputStream; 
     } 
     }; 

     filterChain.doFilter(reqWrapper, respWrapper); 

     // possibly you also need to handle gzipped payload 
     String respPayload = new String(outputStream.getCachedDataAsBytes(), RPCServletUtils.CHARSET_UTF8); 
     String checksum = calculateChecksum(respPayload); 
     httpResp.setHeader(MY_CUSTOM_HEADER_NAME, checksum); 
     httpResp.getOutputStream().write(outputStream.getCachedDataAsBytes()); 
    } else { 
     httpResp.setContentType("text/plain"); 
     httpResp.setStatus(HttpServletResponse.SC_BAD_REQUEST); 
     httpResp.getOutputStream().write("Invalid checksum".getBytes(RPCServletUtils.CHARSET_UTF8)); 
    } 
    } 

    static class ByteArrayServletInputStream extends ServletInputStream { 
    private final InputStream delegate; 

    ByteArrayServletInputStream(byte[] data) throws IOException, ServletException { 
     delegate = new ByteArrayInputStream(data); 
    } 

    @Override 
    public int read() throws IOException { 
     return delegate.read(); 
    } 
    } 

    static class CachingServletOutputStream extends ServletOutputStream { 
    private final ByteArrayOutputStream cache; 

    CachingServletOutputStream() { 
     this.cache = new ByteArrayOutputStream(4096); 
    } 

    @Override 
    public void write(int b) throws IOException { 
     cache.write(b); 
    } 

    @Override 
    public void flush() throws IOException { 
     cache.flush(); 
    } 

    byte[] getCachedDataAsBytes() { 
     return cache.toByteArray(); 
    } 
    } 
}