我需要使用okhttp将apk中捆绑的二进制文件上传到服务器。使用urlconnection,您只需获取资产的输入流,然后将其放入您的请求中。但是,okhttp只提供上传字节数组,字符串或文件的选项。由于您无法获取apk中捆绑的资产的文件路径,因此将文件复制到本地文件目录的唯一选项(我宁愿不这样做)然后将文件提供给okhttp?有没有办法简单地使用assetinputstream直接向Web服务器发出请求?
编辑:我使用了接受的答案,但我没有创建静态实用程序类,而只是将子类化为RequestBody public class InputStreamRequestBody extends RequestBody {
private InputStream inputStream;
private MediaType mediaType;
public static RequestBody create(final MediaType mediaType, final InputStream inputStream) {
return new InputStreamRequestBody(inputStream, mediaType);
}
private InputStreamRequestBody(InputStream inputStream, MediaType mediaType) {
this.inputStream = inputStream;
this.mediaType = mediaType;
}
@Override
public MediaType contentType() {
return mediaType;
}
@Override
public long contentLength() {
try {
return inputStream.available();
} catch (IOException e) {
return 0;
}
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(inputStream);
sink.writeAll(source);
} finally {
Util.closeQuietly(source);
}
}
}
我对这种方法唯一关心的是inputstream.available()对于内容长度的不可靠性。静态构造函数是为了匹配okhttp的内部实现
答案 0 :(得分:30)
您可能无法使用库直接执行此操作,但您可以创建一个小实用程序类来为您执行此操作。然后,您可以在任何需要的地方重复使用它。
public class RequestBodyUtil {
public static RequestBody create(final MediaType mediaType, final InputStream inputStream) {
return new RequestBody() {
@Override
public MediaType contentType() {
return mediaType;
}
@Override
public long contentLength() {
try {
return inputStream.available();
} catch (IOException e) {
return 0;
}
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(inputStream);
sink.writeAll(source);
} finally {
Util.closeQuietly(source);
}
}
};
}
}
然后简单地使用它
OkHttpClient client = new OkHttpClient();
MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
InputStream inputStream = getAssets().open("README.md");
RequestBody requestBody = RequestBodyUtil.create(MEDIA_TYPE_MARKDOWN, inputStream);
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
Log.d("POST", response.body().string());
此示例代码基于this代码。将Assets
文件名和MediaType
替换为您自己的名称。
答案 1 :(得分:0)
我知道它来晚了,但总比没有好。
如果您不知道数据的大小,这里的技巧就是可以跳过content-length标头,并用Http1.1 transfer-encoding替换它:Chuncked
有关更多信息,请阅读https://www.oracle.com/technical-resources/articles/javame/chunking.html
答案 2 :(得分:-1)
使用snoopy api太简单了:如果不包括标识符定义,则只需一行代码:)
URI uri = ...;
Path fileToUpload = ...;
Snoopy.builder()
.config(SnoopyConfig.defaults())
.build()
.post(uri)
.followRedirects(true)
.failIfNotSuccessfulResponse(true)
.body(fileToUpload)
.consumeAsString();
https://bitbucket.org/abuwandi/snoopy
仍然没有android版本,但即将发布...