okhttp文件上傳
1. Android Q 上基於 OkHttp 上傳(大)文件的實現
如圖,RequestBody 有好幾個 create 方法,可以滿足不同場景下的內容上傳,比如字元串、位元組數組和文件。
顯然,字元串和位元組數組是不能上傳大文件的,均可能 OOM。
那麼,就只能使用 RequestBody create(MediaType contentType, File file) 方法了。正常情況下也是沒什麼問題的,但是在 Android Q 上,由於存儲許可權的變更,將導致無法直接訪問從內容庫所選擇的文件。
得到如下日誌:
可見,即使通過 uri 得到了文件的真實路徑,也是無法直接訪問的。
通過上面的實驗可以看到,我們是無法直接通過 File 相關的 API 訪問原始文件的,但是我們卻可以通過 ContentResolver 得到原始文件的流。
類似地,可以基於流或者 FileDescriptor 對圖片解碼成 Bitmap,參考:
2. android 怎麼多圖上傳 okhttp
android上傳圖片是先將圖片文件轉換成流文件:可用以下代碼轉換流文件,imgPath為圖片的完整地址
//圖片轉化成base64字元串
public static String imgToBase64(String imgPath) {
InputStream in = null;
byte[] data = null;
//讀取圖片位元組數組
try {
in = new FileInputStream(imgPath);
data = new byte[in.available()];
in.read(data);
in.close();
}
catch (IOException e){
e.printStackTrace();
}
//對位元組數組Base64編碼
sun.misc.BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);//返回Base64編碼過的位元組數組字元串
}
然後圖片文件就成為一串字元串啦,傳遞方法和普通字元串一樣,多圖使用分號隔開即可,後台收到後直接將流文件轉換成圖片保存即可。
3. android okhttp上傳文件mediatype有哪些
/**
* @param mediaType MediaType
* @param uploadUrl put請求地址
* @param localPath 本地文件路徑
* @return 響應的結果 和 HTTP status code
* @throws IOException
*/
public String put(MediaType mediaType, String uploadUrl, String localPath) throws IOException {
File file = new File(localPath);
RequestBody body = RequestBody.create(mediaType, file);
Request request = new Request.Builder()
.url(uploadUrl)
.put(body)
.build();
Response response = client.newCall(request).execute();
return response.code()+ ":" + response.body().string() ;
}
//上傳JPG圖片
public String putImg(String uploadUrl, String localPath) throws IOException {
MediaType Image = MediaType.parse("image/jpeg; charset=utf-8");
4. okhttp 上傳文件socket關閉怎麼解決
使用okhttp上傳文件時,每次上傳超過5M的文件就會失敗, java.net.SocketException: sendto failed: EPIPE (Broken pipe)
原因是okhttp的請求頭RequestBody出現了問題
原襪坦代碼:
RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(), RequestBody.create(null, file))
.addFormDataPart("filekey", fileKey)
.addFormDataPart("isSend", "true")
.addPart(Headers.of("Content-Disposition", "告凳桐form-data; name=\"another\粗陵";filename=" + file.getName() + "")
,RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
改正後的代碼,刪除了addPart
RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(), RequestBody.create(null, file))
.addFormDataPart("filekey", fileKey)
.addFormDataPart("isSend", "true")
.build();
5. 重識OkHttp——更深入了解如何使用
OkHttp作為square公司出品的一個網路請求框架,應該算是目前Android端最火爆的網路框架了。我公司目前的項目中採用的都是Rxjava結合Retrofit進行網路請求的處理,對於底層真正實現網路請求的OkHttp關注的不是很多。最近探究了一下OkHttp的源碼,對OkHttp的使用有了一些新的認識,在此做一下總結。
OkHttp作為當前Android端最火熱的網路請求框架,必然有很多的優點。
對於客戶端來講,我們關注的就是把正確的請求發送到服務端並拿到結果來進行處理。在OkHttp中,我認為可以分為3個部分:
OkHttp中通過建造者模式來構建OkHttpClient、Request和Response。對於客戶端來講,我們不需要過多關注Response是如何構建的,因為這個是OkHttp對響應結果進行了封裝處理。我們只關注請求Request和客戶端OkHttpClient如何構建即可。
Request採用建造者模式來配置url,請求方法method、header、tag和cacheControl。
OkHttp採用POST方法向伺服器發送一個請求體,在OkHttp中這個請求體是RequestBody。這個請求體可以是:
RequestBody有幾個靜態方法用於創建不同類型的請求體:
最終都是相當於重寫了RequestBody的兩個抽象方法來寫入流,如果傳遞流類型的參數,只要重寫這兩個抽象方法即可。
例如,我們提交一個String:
提交File:
提交流:
對於提交表單和分塊請求,OkHttp提供了兩個RequestBody的子類, FormBody 和 MultipartBody
FormBody也是採用建造者模式, 這個很簡單,添加key-value形式的鍵值對即可。
添加鍵值對有兩個方法:
例如:
MultipartBody也是採用建造者模式,MultipartBody.Builder可以構建兼容Html文件上傳表單的復雜請求體。每一部分的多塊請求體都是它自身的請求體,並且可以定義它自己的請求頭。如果存在的話,這些請求頭用來描述這部分的請求體。例如Content-Disposition、Content-Length 和 Content-Type如果可用就會被自動添加到頭。
MIME類型有:
有幾個主要的方法:
例如提交一個圖片文件:
OkHttpClient採用建造者模式,通過Builder可以配置連接超時時間、讀寫時間,是否緩存、是否重連,還可以設置各種攔截器interceptor等。
建議在一個App中,OkHttpClient保持一個實例。一個OkHttpClient支持一定數量的並發,請求同一個主機最大並發是5,所有的並發最大是64。這個與OkHttp中的調度器Dispatcher有關,可以設置並發數。本文不對Dispatcher進行討論。
一個例子:
OkHttpClient支持單獨配置,例如原來設置不同的請求時間,可以通過OkHttpClient的newBuilder()方法來重新構造一個OkHttpClient。例如:
上面已經講了如何創建Request和OkHttpClient,剩下的就是發送請求並得到伺服器的響應了。OkHttp發送請求可分為同步和非同步。OkHttpClient首先通過Request構建一個Call,通過這個Call去執行同步或者非同步請求。
同步方式,調用Call的execute()方法,返回Response,會阻塞當前線程:
非同步方式,調用Call的enqueue(CallBack callBack)方法,會在另一個線程中返回結果。
為了緩存響應,需要一個可讀寫並且設置大小Size的緩存目錄。緩存目錄需要私有,其它不信任的應用不能訪問這個文件。
如果同時有多個緩存訪問同一個緩存目錄會報錯。所以最好只在App中初始化一次OkHttpClient,給這個實例配置緩存,在整個App生命周期內都用這一個緩存。否則幾個緩存會相互影響,導致緩存出錯,引起程序崩潰。
響應緩存採用Http頭來配置,你可以添加這樣的請求頭 Cache-Control: max-stale=3600 。 max-age 指的是客戶端可以接收生存期不大於指定時間(以 秒 為單位)的響應。
為了防止響應使用緩存,可以用 CacheControl.FORCE_NETWORK 。為了防止使用網路,採用 CacheControl.FORCE_CACHE 。
調用Call.cancel()方法可以立即取消一個網路請求。如果當前線程正在寫request或者讀response會報IO異常。如果不再需要網路請求,採用這種方法是比較方便的。例如在App中返回了上一頁。無論是同步還是非同步的請求都可以被取消。
可以通過Response的code來判斷請求是否成功,如果伺服器返回的有數據,可以通過Response的body得到一個ResponseBody讀取。
如果採用ResponseBody的string()方法會一次性把數據讀取到內存中,如果數據超過1MB可能會報內存溢出,所以對於超過1MB的數據,建議採用流的方式去讀取,如ResponseBody的byteStream()方法。
需要說明的是:
OkHttp中的很多類都用到了建造者模式,可以根據需要靈活配置。採用建造者模式的有:
如果單獨使用OkHttp進行網路請求,通常需要開發者自己再封裝一下,如果不想重復造輪子,Github上面的有一些優秀開源庫可以拿來使用(本文只列出star較多的幾個):
OkHttp官方Wiki文檔
6. Okhttp 使用(同步、非同步/get、post/上傳文件)
目前Android端調用網路請求最常用的框架就是OKHttp,目前項目中也經常會用到。OKHTTP有哪些特點呢?下面是官網給出的OKHTTP的特點:
官網地址: https://square.github.io/okhttp/
想要詳細了解HTTP/2,可以參考: https://www.jianshu.com/p/828a29bced9f
接下來就可以愉快的開始使用OKhttp進行開發了。
OKhttpclient通過builder構建,構建的時候涉及到很多配置項,本次簡單對其中一些配置項做了說明,後續會對一些重要的配置項做專題說明正察。在實際的項目中的配置項根據項目具體需求進行配置。
上述配置項中比較常用的有
同步get請求會阻塞當前線程直到返回舉枝茄結果,請求大致分為四個步驟:
非同步請求方式的步驟和上述前兩個步驟基本搭拍一致,主要發起請求的方式發生了變化,結果通過回調返回。這種請求方式對請求的線程沒有限制。
與get請求方式不同的是post請求需要構建RequestBody,在請求時攜帶RequestBody。
7. okhttp3使用詳解get怎麼傳參數
kHttp 可以做很多事,包括上傳字元串、上傳文件、上傳流、上傳表格參數、上傳多部分的請求、響應 Json、響應緩存等。目前主要流行 Json 數據通信,所以我們就來講講基於 Json 通信的 GET 和 POST 請求與響應。
2 下載 OkHttp
介紹了這么多理論知識,接下來就進入實戰階段了,首先下載 OkHttp 的 jar 包,可以去 GitHub 下載最近的包。
這是最新下載地址:https://search.maven.org/remote_content?g=com.squareup.okhttp3&a=okhttp&v=LATEST
當然,你也可以在項目中直接添加編譯(用於 Android Studio):compile 'com.squareup.okhttp3:okhttp:3.2.0'
OkHttp 的項目地址:https://github.com/square/okhttp
除此之外,還需要添加一個 OkHttp 的依賴包:okio.jar,下載地址:https://search.maven.org/remote_content?g=com.squareup.okio&a=okio&v=LATEST
項目地址:https://github.com/square/okio
編譯地址:compile 'com.squareup.okio:okio:1.6.0'
3 GET 請求
我們從最簡單的 Http 請求開始學起,首先需要獲取一個 OkHttpClient 對象,方法如下:
[java] view plain print?
8. okhttp最大支持上傳多大的文件
/**
* 上傳文件
* @param actionUrl 連接地址
* @param paramsMap 參數
* @param callback 回調
* @param <T>
*/
public static <T>void upLoadFile(String actionUrl, HashMap<String, Object> paramsMap, Callback callback) {
// RequestBody requestBody = new MultipartBuilder() //建立請求的內容
// .type(MultipartBuilder.FORM)//表單形式
// .addFormDataPart("token", token)//攜帶的參數
// .addFormDataPart("file", file.getName(), RequestBody.create(null, file))//第一個參數是伺服器接收的名稱,第二個是上傳文件的名字,第三個是上傳的文件
// .build();
// Request request = new Request.Builder()//建立請求
// .url(url)//請求的地址
// .post(requestBody)//請求的內容(上面建立的requestBody)
// .build();
try {
OkHttpClient okHttpClient = new OkHttpClient();
MultipartBuilder builder = new MultipartBuilder();
builder.type(MultipartBuilder.FORM);
//追加參數
for (String key : paramsMap.keySet()) {
Object object = paramsMap.get(key);
if (!(object instanceof File)) {
builder.addFormDataPart(key, object.toString());
} else {
File file = (File) object;
builder.addFormDataPart(key, file.getName(), RequestBody.create(null, file));
}
}
//創建RequestBody
RequestBody body = builder.build();
//創建Request
final Request request = new Request.Builder().url(actionUrl).post(body).build();
HLog.v("upLoadFile","upLoadFile",request.urlString());
Call call=okHttpClient.newCall(request);
call.enqueue(callback);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
9. 為什麼okhttpclient不能builder
一、概述
最近在群里聽到各種討論okhttp的話題,可見okhttp的口碑相當好了。再加上Google貌似在6.0版本裡面刪除了HttpClient相關API,對於這個行為不做評價。為了更好的在應對網路訪問,學習下okhttp還是蠻必要的,本篇博客首先介紹okhttp的簡單使用,主要包含:
一般的get請求
一般的post請求
基於Http的文件上傳
文件下載
載入圖片
支持請求回調,直接返回對象、對象集合
支持session的保持
最後會對上述幾個功能進行封裝,完整的封裝類的地址見:https://github.com/hongyangAndroid/okhttp-utils
使用前,對於Android Studio的用戶,可以選擇添加:
compile 'com.squareup.okhttp:okhttp:2.4.0'1
或者Eclipse的用戶,可以下載最新的jar okhttp he latest JAR ,添加依賴就可以用了。
注意:okhttp內部依賴okio,別忘了同時導入okio:
gradle: compile 'com.squareup.okio:okio:1.5.0'
最新的jar地址:okio the latest JAR
二、使用教程
(一)Http Get
對了網路載入庫,那麼最常見的肯定就是http get請求了,比如獲取一個網頁的內容。
//創建okHttpClient對象
OkHttpClient mOkHttpClient = new OkHttpClient();
//創建一個Request
final Request request = new Request.Builder()
.url("https://github.com/hongyangAndroid")
.build();
//new call
Call call = mOkHttpClient.newCall(request);
//請求加入調度
call.enqueue(new Callback()
{
@Override
public void onFailure(Request request, IOException e)
{
}
@Override
public void onResponse(final Response response) throws IOException
{
//String htmlStr = response.body().string();
}
}); 以上就是發送一個get請求的步驟,首先構造一個Request對象,參數最起碼有個url,當然你可以通過Request.Builder設置更多的參數比如:header、method等。
然後通過request的對象去構造得到一個Call對象,類似於將你的請求封裝成了任務,既然是任務,就會有execute()和cancel()等方法。
最後,我們希望以非同步的方式去執行請求,所以我們調用的是call.enqueue,將call加入調度隊列,然後等待任務執行完成,我們在Callback中即可得到結果。
看到這,你會發現,整體的寫法還是比較長的,所以封裝肯定是要做的,不然每個請求這么寫,得累死。
ok,需要注意幾點:
onResponse回調的參數是response,一般情況下,比如我們希望獲得返回的字元串,可以通過response.body().string()獲取;如果希望獲得返回的二進制位元組數組,則調用response.body().bytes();如果你想拿到返回的inputStream,則調用response.body().byteStream()
看到這,你可能會奇怪,竟然還能拿到返回的inputStream,看到這個最起碼能意識到一點,這里支持大文件下載,有inputStream我們就可以通過IO的方式寫文件。不過也說明一個問題,這個onResponse執行的線程並不是UI線程。的確是的,如果你希望操作控制項,還是需要使用handler等,例如:
@Override
public void onResponse(final Response response) throws IOException
{
final String res = response.body().string();
runOnUiThread(new Runnable()
{
@Override
public void run()
{
mTv.setText(res);
}
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
我們這里是非同步的方式去執行,當然也支持阻塞的方式,上面我們也說了Call有一個execute()方法,你也可以直接調用call.execute()通過返回一個Response。
(二) Http Post 攜帶參數
看來上面的簡單的get請求,基本上整個的用法也就掌握了,比如post攜帶參數,也僅僅是Request的構造的不同。
Request request = buildMultipartFormRequest(
url, new File[]{file}, new String[]{fileKey}, null);
FormEncodingBuilder builder = new FormEncodingBuilder();
builder.add("username","張鴻洋");
Request request = new Request.Builder()
.url(url)
.post(builder.build())
.build();
mOkHttpClient.newCall(request).enqueue(new Callback(){});12345678910
大家都清楚,post的時候,參數是包含在請求體中的;所以我們通過FormEncodingBuilder。添加多個String鍵值對,然後去構造RequestBody,最後完成我們Request的構造。
後面的就和上面一樣了。
(三)基於Http的文件上傳
接下來我們在介紹一個可以構造RequestBody的Builder,叫做MultipartBuilder。當我們需要做類似於表單上傳的時候,就可以使用它來構造我們的requestBody。
File file = new File(Environment.getExternalStorageDirectory(), "balabala.mp4");
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(Headers.of(
"Content-Disposition",
"form-data; name=\"username\""),
RequestBody.create(null, "張鴻洋"))
.addPart(Headers.of(
"Content-Disposition",
"form-data; name=\"mFile\";
filename=\"wjd.mp4\""), fileBody)
.build();
Request request = new Request.Builder()
.url("http://192.168.1.103:8080/okHttpServer/fileUpload")
.post(requestBody)
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback()
{
//...
});2526
上述代碼向伺服器傳遞了一個鍵值對username:張鴻洋和一個文件。我們通過MultipartBuilder的addPart方法可以添加鍵值對或者文件。
其實類似於我們拼接模擬瀏覽器行為的方式,如果你對這塊不了解,可以參考:從原理角度解析Android (Java) http 文件上傳
ok,對於我們最開始的目錄還剩下圖片下載,文件下載;這兩個一個是通過回調的Response拿到byte[]然後decode成圖片;文件下載,就是拿到inputStream做寫文件操作,我們這里就不贅述了。
關於用法,也可以參考泡網OkHttp使用教程
接下來我們主要看如何封裝上述的代碼。
三、封裝
由於按照上述的代碼,寫多個請求肯定包含大量的重復代碼,所以我希望封裝後的代碼調用是這樣的
附上出處鏈接:http://blog.csdn.net/lmj623565791/article/details/47911083