我在Android项目中使用Retrofit 1.6.0,
请求网址:
https://example.com/image/thumbs/filename/sample.png
我的界面是这样的:
public interface ImageService {
@GET("/image/thumbs/filename/{filename}")
@Streaming
void getThumbs(
@Path("filename") String filename,
Callback<Response> callback
);
}
HTTP请求成功,但发生了一些错误
D/Retrofit(27613): ---> HTTP GET https://example.com/image/thumbs/filename/sample.png
D/Retrofit(27613): ---> END HTTP (no body)
D/Retrofit(27613): <--- HTTP 200 https://example.com/image/thumbs/filename/sample.png (451ms)
D/Retrofit(27613): : HTTP/1.1 200 OK
D/Retrofit(27613): Connection: Keep-Alive
D/Retrofit(27613): Content-Disposition: inline; filename="sample.png"
D/Retrofit(27613): Content-Type: image/png; charset=binary
D/Retrofit(27613): Date: Wed, 11 Jun 2014 06:02:31 GMT
D/Retrofit(27613): Keep-Alive: timeout=5, max=100
D/Retrofit(27613): OkHttp-Received-Millis: 1402466577134
D/Retrofit(27613): OkHttp-Response-Source: NETWORK 200
D/Retrofit(27613): OkHttp-Sent-Millis: 1402466577027
D/Retrofit(27613): Server: Apache/2.2.22 (Ubuntu)
D/Retrofit(27613): Transfer-Encoding: chunked
D/Retrofit(27613): X-Powered-By: PHP/5.4.28-1+deb.sury.org~precise+1
D/Retrofit(27613): ---- ERROR https://example.com/image/thumbs/filename/sample.png
D/Retrofit(27613): java.io.UnsupportedEncodingException: binary
D/Retrofit(27613): at java.nio.charset.Charset.forNameUEE(Charset.java:322)
D/Retrofit(27613): at java.lang.String.<init>(String.java:228)
D/Retrofit(27613): at retrofit.RestAdapter.logAndReplaceResponse(RestAdapter.java:478)
D/Retrofit(27613): at retrofit.RestAdapter.access$500(RestAdapter.java:109)
D/Retrofit(27613): at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:333)
D/Retrofit(27613): at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
D/Retrofit(27613): at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
D/Retrofit(27613): at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
D/Retrofit(27613): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
D/Retrofit(27613): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
D/Retrofit(27613): at retrofit.Platform$Android$2$1.run(Platform.java:142)
D/Retrofit(27613): at java.lang.Thread.run(Thread.java:841)
D/Retrofit(27613): Caused by: java.nio.charset.UnsupportedCharsetException: binary
D/Retrofit(27613): at java.nio.charset.Charset.forName(Charset.java:309)
D/Retrofit(27613): at java.nio.charset.Charset.forNameUEE(Charset.java:320)
D/Retrofit(27613): ... 11 more
D/Retrofit(27613): ---- END ERROR
如何解决这个问题?
答案 0 :(得分:8)
问题是响应中的内容类型标头包含伪造的字符集:
Content-Type: image/png; charset=binary
Retrofit看到了这一点,并推断响应是可以记录的文本。您应该将问题报告给服务器的管理员。
如果您将问题报告给GitHub上的Retrofit问题跟踪器,我们可能会从此问题中恢复而不是崩溃。
答案 1 :(得分:4)
这些天我正在玩rxjava并进行改造,我在这里有一个快速演示。 谈话很便宜,直接向我展示我的代码,希望它有所帮助。
public interface ImageService {
String ENDPOINT = "HTTP://REPLACE.ME";
@GET
@Streaming
Observable<Bitmap> getThumbs(@Url String filepath);
/********
* Helper class that sets up a new services
*******/
class Instance {
static ImageService instance;
public static ImageService get() {
if (instance == null)
instance = newImageService();
return instance;
}
public static ImageService newImageService() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ImageService.ENDPOINT)
.addConverterFactory(BitmapConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit.create(ImageService.class);
}
}
}
我编写了自己的BitmapConverterFactory来将字节流转换为位图:
public final class BitmapConverterFactory extends Converter.Factory {
public static BitmapConverterFactory create() {
return new BitmapConverterFactory();
}
private BitmapConverterFactory() {
}
@Override
public Converter<ResponseBody, Bitmap> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == Bitmap.class) {
return new Converter<ResponseBody, Bitmap>(){
@Override
public Bitmap convert(ResponseBody value) throws IOException {
return BitmapFactory.decodeStream(value.byteStream());
}
};
} else {
return null;
}
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
}
Gradle依赖项:
final RETROFIT_VERSION = '2.0.0-beta3'
compile "com.squareup.retrofit2:retrofit:$RETROFIT_VERSION"
compile "com.squareup.retrofit2:adapter-rxjava:$RETROFIT_VERSION"
干杯, vanvency
答案 2 :(得分:3)
当然我们通常使用Picasso来加载图像,但有时我们确实需要使用Retrofit来加载特殊图像(比如获取验证码图像),你需要为请求添加一些标题,从响应的标题中获取一些值(当然你也可以使用Picasso + OkHttp,但是在一个项目中你已经使用Retrofit来处理大多数网络请求),所以这里介绍如何通过Retrofit 2.0.0实现(我已经在我的项目中实现了)。
关键是您需要使用okhttp3.ResponseBody
来接收响应,否则Retrofit会将响应数据解析为JSON,而不是二进制数据。
代码:
public interface Api {
// don't need add 'Content-Type' header, it not works for Retrofit 2.0.0
// @Headers({"Content-Type: image/png"})
@GET
Call<ResponseBody> fetchCaptcha(@Url String url);
}
Call<ResponseBody> call = api.fetchCaptcha(url);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
if (response.body() != null) {
// display the image data in a ImageView or save it
Bitmap bm = BitmapFactory.decodeStream(response.body().byteStream());
ivCaptcha.setImageBitmap(bm);
} else {
// TODO
}
} else {
// TODO
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
// TODO
}
});
答案 3 :(得分:1)
另一种方法是关闭完整日志记录,因此retrofit.RestAdapter.logAndReplaceResponse不会尝试使用响应正文