代理 InputStream 的方法
Ways to proxy an InputStream
我在 Android 应用程序上使用 Android-Universal-Image-Loader 通过 HTTPS
从远程服务器加载图像。要访问图像,客户端应提供有效令牌,有时服务器会出现 return "expired crsf token" 错误。为了处理此行为,应定义自定义 ImageDownloader。下面是我的实现中应该覆盖的方法的基本实现。
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
HttpURLConnection conn = createConnection(imageUri, extra);
int redirectCount = 0;
while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
conn = createConnection(conn.getHeaderField("Location"), extra);
redirectCount++;
}
InputStream imageStream;
try {
imageStream = conn.getInputStream();
} catch (IOException e) {
// Read all data to allow reuse connection (http://bit.ly/1ad35PY)
IoUtils.readAndCloseStream(conn.getErrorStream());
throw e;
}
if (!shouldBeProcessed(conn)) {
IoUtils.closeSilently(imageStream);
throw new IOException("Image request failed with response code " + conn.getResponseCode());
}
return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength());
}
我想重写它来处理无效令牌错误。例如,如果服务器 return 应该识别出这样的错误,则应该重新生成令牌并重复请求。
我想出的唯一解决方案是这样的(缩短代码):
imageStream = conn.getInputStream();
byte[] body = org.apache.commons.io.IOUtils.toByteArray(imageStream);
if (body.length < 300 // high probability to contain err message
&& isInvalidToken(body)) {
// handle error
}
return new ByteArrayInputStream(body);
考虑到我只将它用于最大 80kb 大小的缩略图,使用这种解决方案是否安全?还有其他解决方案吗?
你考虑过这样的事情吗?
if(conn.getResponseCode()==HttpStatus.RESPONSE_OK) else{ //repeat request...}
您可以在检查响应为 200 OK 后检查有效令牌,如下所示:
conn.getResponseCode() == HttpStatus.RESPONSE_OK && isValidToken(body)
如果不满足这些条件,那么您将相应地处理它,即重复请求 x 次。
我会考虑使用 isValidToken(...)
方法而不是您的 isInvalidToken(...)
,这样您就不必否定该方法的响应。
您的解决方案是安全的,尽管如果您创建实现 InputStream
并包装原始 InputStream
的 ImageDownloaderInputStream
class 会更好。您可以从底层输入流中预加载(缓冲)一些块来检测内容是否有效。
您应该覆盖的唯一方法是 read()。
如果内容有效,可以将缓冲区内容提供给调用者,当缓冲区为空时,直接从底层流式传输InputStream
。
如果内容无效,只需读取另一个流,或 return 零长度流。
public class ImageDownloaderInputStream extends InputStream {
private byte[] buffer = null;
private int bufLen = 0;
private int bufIndex = 0;
private boolean isContentValid;
private InputStream wrapped;
public ImageDownloaderInputStream (InputStream wrapped) {
this.wrapped = wrapped;
}
@Override
public ind read() {
if(buffer == null) {
// check content and fill buffer
this.isContentValid = checkContent();
}
if (this.isContentValid) {
if(bufIndex < bufLen) {
return buffer[bufIndex++] & 0xFF;
} else {
return wrapped.read();
}
} else {
// error handling: zero-length stream
return -1;
}
}
private boolean checkContent() {
// fill the buffer
this.buffer = new byte[1024];
this.bufLen = wrapped.read(this.buffer);
// read more if not enough
// check the content
return true;
// return false;
}
}
我在 Android 应用程序上使用 Android-Universal-Image-Loader 通过 HTTPS
从远程服务器加载图像。要访问图像,客户端应提供有效令牌,有时服务器会出现 return "expired crsf token" 错误。为了处理此行为,应定义自定义 ImageDownloader。下面是我的实现中应该覆盖的方法的基本实现。
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
HttpURLConnection conn = createConnection(imageUri, extra);
int redirectCount = 0;
while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
conn = createConnection(conn.getHeaderField("Location"), extra);
redirectCount++;
}
InputStream imageStream;
try {
imageStream = conn.getInputStream();
} catch (IOException e) {
// Read all data to allow reuse connection (http://bit.ly/1ad35PY)
IoUtils.readAndCloseStream(conn.getErrorStream());
throw e;
}
if (!shouldBeProcessed(conn)) {
IoUtils.closeSilently(imageStream);
throw new IOException("Image request failed with response code " + conn.getResponseCode());
}
return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength());
}
我想重写它来处理无效令牌错误。例如,如果服务器 return 应该识别出这样的错误,则应该重新生成令牌并重复请求。
我想出的唯一解决方案是这样的(缩短代码):
imageStream = conn.getInputStream();
byte[] body = org.apache.commons.io.IOUtils.toByteArray(imageStream);
if (body.length < 300 // high probability to contain err message
&& isInvalidToken(body)) {
// handle error
}
return new ByteArrayInputStream(body);
考虑到我只将它用于最大 80kb 大小的缩略图,使用这种解决方案是否安全?还有其他解决方案吗?
你考虑过这样的事情吗?
if(conn.getResponseCode()==HttpStatus.RESPONSE_OK) else{ //repeat request...}
您可以在检查响应为 200 OK 后检查有效令牌,如下所示:
conn.getResponseCode() == HttpStatus.RESPONSE_OK && isValidToken(body)
如果不满足这些条件,那么您将相应地处理它,即重复请求 x 次。
我会考虑使用 isValidToken(...)
方法而不是您的 isInvalidToken(...)
,这样您就不必否定该方法的响应。
您的解决方案是安全的,尽管如果您创建实现 InputStream
并包装原始 InputStream
的 ImageDownloaderInputStream
class 会更好。您可以从底层输入流中预加载(缓冲)一些块来检测内容是否有效。
您应该覆盖的唯一方法是 read()。
如果内容有效,可以将缓冲区内容提供给调用者,当缓冲区为空时,直接从底层流式传输InputStream
。
如果内容无效,只需读取另一个流,或 return 零长度流。
public class ImageDownloaderInputStream extends InputStream {
private byte[] buffer = null;
private int bufLen = 0;
private int bufIndex = 0;
private boolean isContentValid;
private InputStream wrapped;
public ImageDownloaderInputStream (InputStream wrapped) {
this.wrapped = wrapped;
}
@Override
public ind read() {
if(buffer == null) {
// check content and fill buffer
this.isContentValid = checkContent();
}
if (this.isContentValid) {
if(bufIndex < bufLen) {
return buffer[bufIndex++] & 0xFF;
} else {
return wrapped.read();
}
} else {
// error handling: zero-length stream
return -1;
}
}
private boolean checkContent() {
// fill the buffer
this.buffer = new byte[1024];
this.bufLen = wrapped.read(this.buffer);
// read more if not enough
// check the content
return true;
// return false;
}
}