2013-11-04 21 views
12

Bir Jersey istemcisinden bir Jersey sunucusuna ve geri dosya gönderen basit bir Jersey uygulaması yazmaya çalışıyorum. Ancak, dosyalar yalnızca istemciden sunucuya şifrelenmiş gibi görünür, ancak başka şekilde değil. Bu davranışı nasıl değiştirebileceğimi merak ediyorum.Jersey, yanıt iletisi gövdesi için GZip sıkıştırması kullanmasını nasıl sağlar

ben basit örnekte bu test ediyorum:

açmış dökümü itibaren
public class GZipEncodingTest extends JerseyTest { 

    private static final String PATH = "/"; 
    private static final String QUESTION = "foo", ANSWER = "bar"; 
    private static final String ENCODING_GZIP = "gzip"; 

    @Path(PATH) 
    public static class MyResource { 
    @POST 
    public Response handle(String question) throws IOException { 
     assertEquals(QUESTION, question); 
     return Response.ok(ANSWER).build(); // (1) 
    } 
    } 

    @Override 
    protected Application configure() { 
    enable(TestProperties.LOG_TRAFFIC); 
    enable(TestProperties.DUMP_ENTITY); 
    return new ResourceConfig(MyResource.class, GZipEncoder.class); 
    } 

    @Override 
    @SuppressWarnings("unchecked") 
    protected void configureClient(ClientConfig config) { 
    config.register(new EncodingFeature(ENCODING_GZIP, GZipEncoder.class)); 
    } 

    @Test 
    public void testHeaders() throws Exception { 
    Response response = target().path(PATH).request().post(Entity.text(QUESTION)); 
    assertEquals(ANSWER, response.readEntity(String.class)); 
    } 
} 

, ben istek amaçlanmaktadır olarak söyleyebilirim: İçerik kodlama başlığında işaret ve istek mesajı gövde üzerine uygulanır . Accept-Encoding da ayarlanır. Sunucu uygulanan gzip sıkıştırmasını anlar ve istek mesajının gövdesini açar. Bununla birlikte, istemcinin gzipli bir yanıtı kabul ettiği ve yanıt mesajı gövdesini sıkıştırılmamış olarak gönderdiği gerçeğini göz ardı eder.

Ben çizgi içinde encoding(ENCODING_GZIP) ekleme

(1) Response -Builder zincirinde, ben arıyorum sonucu almak. Ancak, yalnızca istekte kabul edilebilir olarak işaretlenmişse kodlamayı uygulamak istiyorum. Dahası, bu özellik uygulamasına sadece belirli cevaplar için değil, aynı zamanda da çok geniş bir yelpazede başvurmak istiyorum.

Ben tabii ki WriterInterceptor ile elle böyle bir özelliği ekleyebilirsiniz:

public class GZipWriterInterceptor implements WriterInterceptor { 
    @Override 
    public void aroundWriteTo(WriterInterceptorContext context) 
     throws IOException, WebApplicationException { 
    context.getHeaders().add(HttpHeaders.CONTENT_ENCODING, ENCODING_GZIP); 
    context.proceed(); 
    } 
} 

ama bu gereksiz kazan plaka olduğuna inanıyorum.

EncodingFeature yalnızca istemci kitaplığının bir parçası gibi görünüyor. Temel olarak, istekte bulunan kodlamayı kabul kodlama yoluyla önerdiğinde Jersey sunucusunun verileri gzip olarak kodlamasını sağlamak için bir olasılık arıyorum.

Web'de çözüm aramaya çalıştığımda bol miktarda buluyorum. Bunların çoğu Jersey 1 ile ilgilidir. Bazıları GrizzlyServer'a (Jersey'e özgü olan ve JAX-RS değil) bir dinleyici eklemeyi önerir. Ben insanlar bulundu

  • org.glassfish.grizzly.http.GZipContentEncoding
  • org.glassfish.jersey.message.GZipEncoder
  • org.glassfish.grizzly.compression.zip.GZipEncoder
  • org.glassfish.grizzly.compression.zip.GZipDecoder
  • org.glassfish.grizzly.compression.zip.GZipFilter

: Sonra GZip kodlamayı öneririz Jersey 2 bağımlılık ağacındaki bol sınıfları vardır web, hatta sizden herhangi birini kullanmanızı önerir gh org.glassfish.jersey'un gerçek bir Jersey bağımlılığı olduğundan doğru seçim gibi gözüktüğünü düşünüyorum. ApacheConnector ilgili kütüphanelerde bulunanlardan bahsetmemek. Hangisini kullanmam gerektiğini bilmiyorum.

+0

Bkz. Http://stackoverflow.com/questions/19751014/gzip-encoding-in-jersey-2-grizzly –

+0

Sorunum aslında biraz daha karmaşıktır. Gzip kodlamasını yeniden oluşturmak istedim. Soruyu burada yeniden düzenledim: http://stackoverflow.com/questions/19794014/why-does-jersey-swallow-my-content-encoding-header –

+0

Hala bu sorunu çözerek * resmi çözümü * yeniden oluşturmaya çalışıyorum GZip örnek çalışması. Ancak, sadece bir şekilde çalışıyorum ama diğerini değil. Önerdiğiniz çözüm, bana karşı bir hack gibi görünüyor, dürüst olmak gerekirse. –

cevap

16

Bunu Jersey kütüphanesine bakarak anladım. sunucu tarafında, aşağıdaki yapılandırma gereklidir: Oturumu altında

@Override 
@SuppressWarnings("unchecked") 
protected Application configure() { 
    ResourceConfig resourceConfig = new ResourceConfig(MyResource.class); 
    EncodingFilter.enableFor(resourceConfig, GZipEncoder.class); 
    return resourceConfig; 
} 

, EncodingFilter#enableFor(ResourceConfig.Class<? extends ContentEncoder>[]) bir EncodingFilter verilen ResourceConfig belirtilen GZipEncoder kaydeder.

Sanırım kayıttaki bu sapmanın ardında yatan sebep, herhangi bir kodlamanın iki aşamada gerçekleşmesidir. İlk olarak,değeriniolarak ayarlayarak yanıtın üstbilgisini EncodingFilter olan EncodingFilter.Aynı zamanda, bu akış oluşturulmadan önce filtre çalıştırıldığından, filtre ileti gövdesinin varlık akışını değiştiremez. Bu nedenle, dere modifikasyon filtresinin işlem sonrasında ve ayrıca işletme akımının oluşturulmasından sonra tetiklenir bir WriterInterceptor tarafından işlenmesi gerekir. Bu nedenle

, sadece GZipEncoder kayıt istek kod çözme için çalışacaktır zaman Content-Encoding başlığı, sunucunun oluşturulmasından bağımsız olarak istemci tarafından gzip olarak ayarlanır.

'GZipWriterInterceptor' ile verdiğim örnek temel olarak EncodingFilter'un zayıf uygulanmış bir sürümüdür. Tabii ki, başlık bir engelleyicide değil, bir filtrede ayarlanmalıdır. Bu says in the documentation:

filtre temel olarak HTTP başlıkları, tanım-ve/veya HTTP yöntemleri gibi istek ve tepki parametrelerinin kontrol edilmesi için tasarlanmıştır ise, önleyicilerin işletme giriş manipüle ile, varlıkları işlemek için amaçlanan/çıkış

akışları

Bu nedenle, gzip kodlaması sadece bir GZipEncoder kayıt edilerek etkinleştirilemez, bunun da bir filtreyle birlikte kaydedilmesi gerekir. Bu yüzden her ikisinin de bir Feature paketinde toplanmasını bekledim.

Önemli:: Jersey'de iki adet EncodingFilter sınıfı vardır. Biri müşteriye ait, diğeri sunucu uygulamasına ait. Yanlış olanı kullanmayın çünkü temelde farklı şeyler yaparlar. Ne yazık ki, istemci arayüzüne güvendikleri için her ikisini de birim testlerini çalıştırırken sınıf yolunuzda olacak.

+1

çok korkunç ... Bu çözüm sadece Jersey 2.0+ – Filipe

+0

için 1x (1.6) için herhangi bir işaretçi mi? –