Okhttp基礎使用和注意事項

基本概念

官網 https://square.github.io/okhttp/

github地址 https://github.com/square/okhttp

okhttp4.x和okhttp3.x;4.x使用kotlin來編寫的

 

Request

Request類封裝了請求報文信息:請求的Url地址、請求的方法(如GET、POST等)、各種請求頭(如Content-Type、Cookie)以及可選的請求體。一般通過內部類Request.Builder的鏈式調用生成Request對象。

 

Call

Call代表了一個實際的HTTP請求,它是連接Request和Response的橋樑,通過Request對象的newCall()方法可以得到一個Call對象。Call對象既支持同步獲取數據,也可以異步獲取數據。

執行Call對象的execute()方法,會阻塞當前線程去獲取數據,該方法返回一個Response對象。

執行Call對象的enqueue()方法,不會阻塞當前線程,該方法接收一個Callback對象,當異步獲取到數據之後,會回調執行Callback對象的相應方法。如果請求成功,則執行Callback對象的onResponse方法,並將Response對象傳入該方法中;如果請求失敗,則執行Callback對象的onFailure方法。

 

Response

Response類封裝了響應報文信息:狀態嗎(200、404等)、響應頭(Content-Type、Server等)以及可選的響應體。可以通過Call對象的execute()方法獲得Response對象,異步回調執行Callback對象的onResponse方法時也可以獲取Response對象。

 

應用場景

   使用OkHttp執行get請求和帶參數的get請求;

  使用OkHttp執行post請求、帶參數的post請求;

  支持contentType爲none、application/json、form-data、application/x-www-form-urlencoded

  圖從postman截取

代碼實現如下:

 getUrl 方法: 用於拼接url;post或者get請求都可能會需要拼接url;

                       Okhttp拼接url功能不錯,沒有?會自動添加?;有?會直接在後面添加參數。

curl -X GET "http://localhost:9099/requestDemo/getDemo?name=111&strDemo=222" -H "accept: */*"

getBody方法:用於拼接post請求的body內容;以下是OkHttp的幾種body和對應關係

 

@Slf4j
public class OkhttpUtils {
 
   private static OkHttpClient okHttpClient = new OkHttpClient.Builder().readTimeout(6, TimeUnit.SECONDS).build();
 
   private static final MediaType JSON = MediaType.parse("application/json");
 
   private static final String MEDIATYPE_NONE = "none";
   private static final String MEDIATYPE_JSON = "application/json";
   private static final String MEDIATYPE_FORM = "form-data";
   private static final String MEDIATYPE_FORM_URLENCODED = "application/x-www-form-urlencoded";
 
    /**
      * @Author JackZhou
      * @Description  執行get請求
     **/
    public static String execRequest(String url, Map<String, String> headers){
        Request.Builder requestBuilder = new Request.Builder().url(url);
        if(headers != null && headers.size() >0 ){
            headers.entrySet().stream().forEach(entry -> requestBuilder.header(entry.getKey(), entry.getValue()));
        }
        Request request = requestBuilder.url(url).build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            return  response.body().string();
        } catch (IOException e) {
            log.info("執行http請求出錯,地址:{}", url, e);
            return null;
        }
    }
 
    /**
     * @Author JackZhou
     * @Description  執行post請求
     **/
    public static String execPostRequest(String url, Map<String, String> headers, RequestBody requestBody){
        Request.Builder requestBuilder = new Request.Builder().url(url);
        if(headers != null && headers.size() >0 ){
            headers.entrySet().stream().forEach(entry -> requestBuilder.header(entry.getKey(), entry.getValue()));
        }
        Request request = requestBuilder.url(url).post(requestBody).build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            return  response.body().string();
        } catch (IOException e) {
            log.info("執行http請求出錯,地址:{}", url, e);
            return null;
        }
    }
 
    /**
     * @Author JackZhou
     * @Description  得到post請求的RequestBody
     **/
    public static RequestBody getBody(String type, Map<String, String> formParam, String body){
        switch (type) {
            case MEDIATYPE_JSON:
                if(StringUtils.isEmpty(body)){
                    RequestBody.create(null, "");
                }
                return RequestBody.create(JSON, body);
            case MEDIATYPE_FORM:
                MultipartBody.Builder formBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
                if(formParam != null && formParam.size() >0 ){
                    formParam.entrySet().stream().forEach(entry -> formBuilder.addFormDataPart(entry.getKey(), entry.getValue()));
                }
                return formBuilder.build();
            case MEDIATYPE_FORM_URLENCODED:
                FormBody.Builder builder = new FormBody.Builder();
                if(formParam != null && formParam.size() >0 ){
                    formParam.entrySet().stream().forEach(entry -> builder.add(entry.getKey(), entry.getValue()));
                }
                return builder.build();
            case MEDIATYPE_NONE:
                return RequestBody.create(null, "");
            default:
                throw new IllegalArgumentException("不支持的mediaType:" + type);
        }
    }
 
    /**
     * @Author JackZhou
     * @Description  得到拼接後的url  @RequestParam參數
     **/
    public static String getUrl(String url, Map<String, String> params){
        HttpUrl.Builder builder = HttpUrl.parse(url).newBuilder();
        if(params != null && params.size() > 0){
            params.entrySet().stream().forEach(entry -> builder.addQueryParameter(entry.getKey(), entry.getValue()));
        }
        return builder.build().toString();
    }

測試驗證

@Data
public class Person {
    private String id;
    private String name;
    private int age;
}
@RestController
@Api(tags = "模擬不同的meidaType")
@RequestMapping(value = "/requestDemo")
public class MediaTypeController {
 
    @ApiOperation("模擬普通get請求")
    @RequestMapping(value = "/getDemo", method = RequestMethod.GET)
    public String getDemo(@RequestParam(required = false) String name, @RequestParam(required = false) String strDemo){
        return "success: " + name + ";strDemo:" + strDemo;
    }
 
    @ApiOperation("模擬普通post請求")
    @RequestMapping(value = "/getPost", method = RequestMethod.POST)
    public String postDemo(){
        return "success";
    }
 
    @ApiOperation("模擬普通post 帶參數請求")
    @RequestMapping(value = "/getPostParam", method = RequestMethod.POST)
    public String postParamDemo(@RequestParam(required = false) String name, @RequestParam(required = false) String strDemo){
        return "success:" + name;
    }
 
    @ApiOperation("模擬post xxx-form請求")
    @RequestMapping(value = "/getPostModel", method = RequestMethod.POST)
    public String postModelDemo(@ModelAttribute Person person){
        if(person != null){
            return "success:" + person.getName();
        }else{
            return "success";
        }
    }
 
    @ApiOperation("模擬普通post 傳json請求")
    @RequestMapping(value = "/getPostJson", method = RequestMethod.POST)
    public String postJsonDemo(@RequestBody Person person){
        if(person != null){
            return "success:" + person.getName();
        }else{
            return "success";
        }
    }
 
    @ApiOperation("模擬普通post form請求")
    @RequestMapping(value = "/getPostForm", method = RequestMethod.POST)
    public String postDemo(HttpServletRequest request){
        System.out.println(request.getParameter("name"));
        System.out.println(request.getParameter("strDemo"));
        return "success";
    }
 
}

偷懶,測試main方法;加到OkhttpUtils類中即可

  public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("name", "張三");
        map.put("strDemo", "上山打老虎");
 
        Map<String, String> pMap = new HashMap<>();
        pMap.put("name", "張三");
        pMap.put("id", "11111");
        pMap.put("age", "111");
 
          // 測試get請求、有參無參均可
//        String getUrl = "http://localhost:9099/requestDemo/getDemo";
//        log.info(execRequest(getUrl(getUrl, map), null));
          // 測試基本的post  url後面有參數或者沒有
//        String postUrl = "http://localhost:9099/requestDemo/getPost";
//        //String postUrl = "http://localhost:9099/requestDemo/getPostParam";
//        log.info(execPostRequest(postUrl, null, getBody(MEDIATYPE_NONE, null, null)));
//        log.info(execPostRequest(execRequest(getUrl(getUrl, map), null, getBody(MEDIATYPE_NONE, null, null)));
 
         // 測試post的application/x-www-form-urlencoded 對應@ModelAttribute註解
//        String postUrl = "http://localhost:9099/requestDemo/getPostModel";
//        //log.info(execPostRequest(postUrl, null, getBody(MEDIATYPE_FORM_URLENCODED, null, null)));
//        log.info(execPostRequest(postUrl, null, getBody(MEDIATYPE_FORM_URLENCODED, pMap, null)));
            // 測試post的application/json  對應@RequestBody註解
//         String postUrl = "http://localhost:9099/requestDemo/getPostJson";
//         log.info(execPostRequest(postUrl, null, getBody(MEDIATYPE_JSON, null, "{ \"age\": 11, \"id\": \"sdsb111\", \"name\": \"張三\"}")));
           // 測試post的form-data
//         String postUrl = "http://localhost:9099/requestDemo/getPostForm";
//         log.info(execPostRequest(postUrl, null, getBody(MEDIATYPE_FORM, map, null)));
 
    }

注意事項

 1、如果post請求的內容爲空,不能傳空的requestBody會報錯  

java.lang.IllegalArgumentException: method POST must have a request body 

### 添加以下代碼

#如果post請求的body和contentType爲空
RequestBody.create(null, "")

2、Response需要關閉

有些方法會關閉資源,有些不會,這一點要注意。

response.body().string(); //stirng裏面會關閉資源
response.isSuccessful(); //如果判斷是否 需要response.close()

3、推薦使用OkhttpClient單例

4、壓縮支持

默認開啓壓縮支持,不需要手動設置(手動設置需要更多設置); 原理:使用攔截器,解析壓縮數據

5、默認開啓Keep-Alive;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章