首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >改造+ okhttp :检索GZIPInputStream

改造+ okhttp :检索GZIPInputStream
EN

Stack Overflow用户
提问于 2014-02-05 18:22:39
回答 4查看 9.3K关注 0票数 12

当我使用Refit1.4.1和okHttp1.3.0激活WS上的gzip时,我遇到了问题。

代码语言:javascript
复制
RequestInterceptor requestInterceptor = new RequestInterceptor() {
            @Override
            public void intercept(RequestFacade request) {
                request.addHeader("content-type", "application/json");
                request.addHeader("accept-encoding", "gzip");  // Here is the problem
            }
        }; 
RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint(Constants.HOST)
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .setRequestInterceptor(requestInterceptor)
            .build();

如果我注释了下面的request.addHeader("accept-encoding", "gzip");行,没有问题,但是如果激活了gzip,我就会得到一个错误(我的请求落在failure中)。

这是我在request.addHeader("accept-encoding", "gzip");上的日志

代码语言:javascript
复制
1326               Retrofit  D  : HTTP/1.1 200 OK
  1326               Retrofit  D  Cache-Control: public, max-age=600
  1326               Retrofit  D  Content-Encoding: gzip
  1326               Retrofit  D  Content-Length: 254
  1326               Retrofit  D  Content-Type: application/json
  1326               Retrofit  D  Date: Wed, 05 Feb 2014 20:22:26 GMT
  1326               Retrofit  D  OkHttp-Received-Millis: 1391631746193
  1326               Retrofit  D  OkHttp-Response-Source: NETWORK 200
  1326               Retrofit  D  OkHttp-Selected-Transport: http/1.1
  1326               Retrofit  D  OkHttp-Sent-Millis: 1391631745971
  1326               Retrofit  D  Server: Apache
  1326               Retrofit  D  Vary: Accept-Encoding
  1326               Retrofit  D  X-Powered-By: PHP/5.3.3-7+squeeze18
  1326               Retrofit  D  ������������}�?O�0��~����nHZOH0 �D�ù���?���~w.�:����=�{�
                               ����|A���=�V/~}o�)���&����<�`�6&��ѳ:��5�ke��V�WD�H�
                               ���ud�J5رyp��G�ːg�y�ʴ����Mxq<�#�Rb`Su�@�0��y��lr;�W�2�C3�
                               T��$���.�
                                          ��xѥ���R
                                                   y���hmt����R����o����v��7@P�
                               4Y����
  1326               Retrofit  D  <--- END HTTP (254-byte body)
  1326             System.err  W  retrofit.RetrofitError: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.Ille
                               galStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1
  1326             System.err  W  at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:408)
  1326             System.err  W  at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:262)
  1326             System.err  W  at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:313)
  1326             System.err  W  at retrofit.CallbackRunnable.run(CallbackRunnable.java:38)
  1326             System.err  W  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
  1326             System.err  W  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
  1326             System.err  W  at retrofit.Platform$Android$2$1.run(Platform.java:136)
  1326             System.err  W  at java.lang.Thread.run(Thread.java:841)
  1326             System.err  W  Caused by: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateExcep

我怎么打开gzip?

Thx预先

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-02-05 22:13:17

只需从代码中省略accept-encoding头即可。OkHttp将添加它自己的accept-encoding头,如果服务器用gzip响应,OkHttp将为您默默地解压缩它。

票数 28
EN

Stack Overflow用户

发布于 2014-03-20 15:29:20

在遇到类似的问题(在我的例子中,没有添加任何接受编码头的情况下,它偶尔会失败- gzip响应,留下内容-编码: gzip头,崩溃JSON解析器),并且没有明确的方法,我手动启用了gzip for Retrofit,创建了下面的委托客户端实现。它工作得很好,只是您可能不应该在非常大的响应(例如>250 It )中使用它,因为它们首先被复制到一个字节数组中。

代码语言:javascript
复制
public class GzippedClient implements Client {

    private Client wrappedClient;

    public GzippedClient(Client wrappedClient) {
        this.wrappedClient = wrappedClient;
    }

    @Override
    public Response execute(Request request) throws IOException {
        Response response = wrappedClient.execute(request);

        boolean gzipped = false;
        for (Header h : response.getHeaders()) {
            if (h.getName() != null && h.getName().toLowerCase().equals("content-encoding") && h.getValue() != null && h.getValue().toLowerCase().equals("gzip")) {
                gzipped = true;
                break;
            }
        }

        Response r = null;
        if (gzipped) {
            InputStream is = null;
            ByteArrayOutputStream bos = null;

            try {
                is = new BufferedInputStream(new GZIPInputStream(response.getBody().in()));
                bos = new ByteArrayOutputStream();

                int b;
                while ((b = is.read()) != -1) {
                    bos.write(b);
                }

                TypedByteArray body = new TypedByteArray(response.getBody().mimeType(), bos.toByteArray());
                r = new Response(response.getUrl(), response.getStatus(), response.getReason(), response.getHeaders(), body);
            } finally {
                if (is != null) {
                    is.close();
                }
                if (bos != null) {
                    bos.close();
                }
            }
        } else {
            r = response;
        }
        return r;
    }

}

您还必须向请求中添加接受编码头,例如使用RequestInterceptor。

代码语言:javascript
复制
requestFacade.addHeader("Accept-Encoding", "gzip");

最后,您必须将现有客户端封装到这个新的GzippedClient中,如下所示:

代码语言:javascript
复制
restBuilder.setClient(new GzippedClient(new OkClient(okHttpClient)));

就这样。现在,您的数据将被压缩。

编辑:在OkHttp版本1.5.1中,一个bug (https://github.com/square/okhttp/pull/632)似乎已经修复,它与透明的EDIT相关,这可能(也可能不是)是我最初问题的根源。如果是这样的话,un的偶尔失败可能不再发生,尽管它很少发生,以至于我还不能证实这一点。无论哪种方式,如果您希望依赖自己,而不是透明地添加/移除头和work,那么所描述的解决方案将有效。

票数 2
EN

Stack Overflow用户

发布于 2015-04-08 11:44:37

如果您在HttpEngine库中签入OkHttp,那么您可以在OkHttp库中找到下面的代码,这意味着如果您在请求中手动添加"Accept-Encoding":"gzip“标题,那么un就是您的责任。/** * True if this client added an "Accept-Encoding: gzip" header field and is * therefore responsible for also decompressing the transfer stream. */ private boolean transparentGzip;

因此,如果您手动添加"Accept-Encoding":"gzip“标题,那么在得到响应后,执行un如下所示。

代码语言:javascript
复制
private static String readContentFromTypedInput(TypedInput typedInput){

        InputStreamReader isr = null;
        BufferedReader br = null;
        char[] cbuf = new char[512];
        StringWriter stringWriter = new StringWriter();

        try {
            final InputStream in = typedInput.in();
            boolean isGzipped = GZipper.isGzippped(in);
            if(isGzipped){
                return new String(GZipper.doUnZip(in));
            }
            isr = new InputStreamReader(in);
            br = new BufferedReader(isr);
            while((br.read(cbuf))!= -1){
                stringWriter.write(cbuf);
            }
        } catch (IOException e) {
            throw new InvalidTestCaseException("failed read received content.", e);
        } finally{
            try{
                if(br != null) br.close();
            }catch(IOException e){ 
                //ignore
            }
        }
        return stringWriter.toString().trim();
    }

GZipper.java

代码语言:javascript
复制
public class GZipper{

public static final String DEFAULT_CHARSET = "utf-8";
private static final int BYTE_BLOCK_LENGTH = 1024;

public static byte[] doZip(final String message){
    if(message == null || message.isEmpty()){
        throw new SystemFailedException("Fail to zip - given message is null or empty");
    }
    byte[] gzippped = null;
    try {
        gzippped = doZip(message.getBytes(DEFAULT_CHARSET));
    } catch (Throwable e) {
        throw new SystemFailedException(e.getMessage(), e);
    }
    return gzippped;
}

public static byte[] doZip(final byte[] unzippedMessageByte){
    validate(unzippedMessageByte, "Fail to zip - given bytes is null or empty");

    ByteArrayInputStream is = null;
    ByteArrayOutputStream bos = null;
    GZIPOutputStream gzip_os = null;
    byte[] compressedBytes = null;
    try{
        is = new ByteArrayInputStream(unzippedMessageByte);
        bos = new ByteArrayOutputStream();
        gzip_os = new GZIPOutputStream(bos);
        copy(is, gzip_os);
        gzip_os.finish();
        compressedBytes = bos.toByteArray();
    }catch(IOException e){
        throw new SystemFailedException(e.getMessage(), e);
    }finally{
        try{
            if(is != null){is.close();}
            if(gzip_os != null){gzip_os.close();}
            if(bos != null){bos.close();}
        }catch(IOException e){
            //ignore
        }
    }
    return compressedBytes;
}

public static String doUnZipToString(final byte[] gzippedMessage){
    validate(gzippedMessage, "Fail to unzip - given bytes is null or empty");
    byte[] gzippped = null;
    String unzippedMessage = null;
    try {
        gzippped = doUnZip(gzippedMessage);
        unzippedMessage = new String(gzippped, DEFAULT_CHARSET);
    } catch (Throwable e) {
        throw new SystemFailedException(e.getMessage(), e);
    }
    return unzippedMessage;
}

private static void validate(final byte[] bytes, String failedMessage) {
    if(bytes == null || bytes.length == 0){
        throw new SystemFailedException(failedMessage);
    }
}

public static byte[] doUnZip(InputStream in) {
    if(!(in instanceof ByteArrayInputStream)){
        try {
            return doUnZip(IOUtils.toByteArray(in));
        } catch (IOException e) {
            throw new SystemFailedException(e.getMessage(), e);
        }
    }

     ByteArrayOutputStream bos = null;
     InputStream gzip_is = null;
     byte[] bytes = null;
    try{
        bos = new ByteArrayOutputStream();
        gzip_is = new GZIPInputStream(in);
        copy(gzip_is,bos);
        bytes = bos.toByteArray();
    }catch(IOException e){
        throw new SystemFailedException(e.getMessage(), e);
    }finally{
        try{
            if(gzip_is != null) gzip_is.close();
            if(bos != null) bos.close();
        }catch(IOException e){
            //ignore
        }
    }
    return bytes;
}

public static byte[] doUnZip(final byte[] zippedMessage){
    validate(zippedMessage, "Fail to unzip - given bytes is null or empty");
    ByteArrayInputStream is = null;
    try{
        is = new ByteArrayInputStream(zippedMessage);
        return doUnZip(is);
    }finally{
        try{
            if(is != null) is.close();
        }catch(IOException e){
            //ignore
        }
    }
}

public static String doUnZip(File file){
    validate(file);

    GZIPInputStream gzipInputStream = null;
    StringWriter writer = null;
    String result = "";

    try{
        byte[] buffer = new byte[BYTE_BLOCK_LENGTH];
        gzipInputStream = new GZIPInputStream(new FileInputStream(file));
        writer = new StringWriter();
        while((gzipInputStream.read(buffer)) > 0){
            writer.write(new String(buffer));
            writer.flush();
        }
        result = writer.toString();
    }catch(IOException e){
        //do something to handle exception
    }
    finally{
        try{
            if(writer != null){writer.close();}
            if(gzipInputStream != null){gzipInputStream.close();}
        }catch(IOException e){
            //ignore
        }
    }
    return result;
}

private static void validate(File file) {
    if(file==null || !file.exists()){
        throw new SystemFailedException("Fail to unzip - file is not exist");
    }
}

private static void copy(InputStream in, OutputStream out)throws IOException {
    byte[] buf = new byte[BYTE_BLOCK_LENGTH];
    int len = -1;
    while ((len = in.read(buf, 0, buf.length)) != -1) {
        out.write(buf, 0, len);
    }
}

public static boolean isGzipped(byte[] input){
    return isGzippped(new ByteArrayInputStream(input));
}

public static boolean isGzippped(InputStream in){
    boolean markSupported = in.markSupported();
    boolean result = false;
    try {
        if(markSupported){
            in.mark(0);
            result = (readUShort(in) == GZIPInputStream.GZIP_MAGIC);
            in.reset();
        }
    } catch (Exception e) {
        result = false;
    }
    return result;
}

private static int readUShort(InputStream in) throws IOException {
    int b = readUByte(in);
    return ((int)readUByte(in) << 8) | b;
}

/*
 * Reads unsigned byte.
 */
private static int readUByte(InputStream in) throws IOException {
    int b = in.read();
    if (b == -1) {
        throw new EOFException();
    }
    if (b < -1 || b > 255) {
       b = 0;
    }
    return b;
}

}

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21585347

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档