項(xiàng)目總結(jié)之HttpURLConnection的disconnect的問題
HttpURLConnection的disconnect問題
項(xiàng)目需要存儲(chǔ)文件,但是由于使用百度云平臺(tái)的服務(wù)器,沒有文件寫權(quán)限,輾轉(zhuǎn)使用中間轉(zhuǎn)發(fā)的策略,將文件存儲(chǔ)在公司公網(wǎng)服務(wù)器上,通過云平臺(tái)的文件請(qǐng)求都轉(zhuǎn)發(fā)到文件服務(wù)器。
響應(yīng)轉(zhuǎn)發(fā)過程中,總是得不到轉(zhuǎn)發(fā)的響應(yīng)內(nèi)容。
跟蹤發(fā)現(xiàn)獲取到的URLConnection的輸入流的available總是返回0,導(dǎo)致轉(zhuǎn)發(fā)響應(yīng)內(nèi)容為空。
調(diào)試發(fā)現(xiàn)把 URLConnection的disconnect()調(diào)用代碼注釋掉,能夠轉(zhuǎn)發(fā)成功。
/** ?? ? * 以http方式發(fā)送請(qǐng)求,并將請(qǐng)求響應(yīng)內(nèi)容以String格式返回 ?? ? * @param path ? ?請(qǐng)求路徑 ?? ? * @param method ?請(qǐng)求方法 ?? ? * @param body ? ?請(qǐng)求數(shù)據(jù) ?? ? * @return 返回響應(yīng)的字符串 ?? ? */ ?? ?public static void httpRequestRediret(HttpServletResponse response,String fileName,String path, String method, String body) { ?? ??? ?HttpURLConnection conn = null; ?? ??? ?InputStream inputStream = null; ?? ??? ?try { ?? ??? ??? ?URL url = new URL(path); ?? ??? ??? ?conn = (HttpURLConnection) url.openConnection(); ?? ??? ??? ?conn.setDoOutput(true); ?? ??? ??? ?conn.setDoInput(true); ?? ??? ??? ?conn.setUseCaches(false); ?? ??? ??? ?conn.setRequestMethod(method); ?? ??? ??? ?if (null != body) { ?? ??? ??? ??? ?OutputStream outputStream = conn.getOutputStream(); ?? ??? ??? ??? ?outputStream.write(body.getBytes("UTF-8")); ?? ??? ??? ??? ?outputStream.close(); ?? ??? ??? ?} ?? ??? ??? ?//代理返回流信息 ?? ??? ??? ?inputStream = conn.getInputStream(); ?? ??? ??? ?response.setContentType(conn.getContentType()); ?? ??? ??? ?FileUtil.responseAttachment(fileName,inputStream, response); ?? ??? ?} catch (Exception e) { ?? ??? ??? ?logger.error(e); ?? ??? ?}finally{ ?? ??? ??? ?if(conn!=null){ ?? ??? ??? ??? ?conn.disconnect(); ?? ??? ??? ?} ?? ??? ?} ?? ?}
FileUtil轉(zhuǎn)發(fā)附件
/** ?? ? * Http響應(yīng)內(nèi)容為附件 ?? ? * @param file ?? ? * @param response ?? ? */ ?? ?public static void responseAttachment(String fileName ,InputStream in,HttpServletResponse response){ ?? ??? ?if(response==null||in==null||fileName==null){ ?? ??? ??? ?return; ?? ??? ?} ?? ??? ?BufferedInputStream bis = null; ?? ??? ?BufferedOutputStream bos = null; ?? ??? ?byte[] buff = new byte[1024]; ?? ??? ?int bytesRead; ?? ??? ?try{ ?? ??? ??? ?response.setHeader("Content-disposition", "attachment; filename=" ?? ??? ??? ??? ??? ?+ new String(fileName.getBytes("utf-8"), "ISO8859-1")); ?? ??? ??? ?response.setHeader("Content-Length", String.valueOf(in.available())); ?? ??? ??? ?bis = new BufferedInputStream(in); ?? ??? ??? ?bos = new BufferedOutputStream(response.getOutputStream()); ?? ??? ??? ?while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) { ?? ??? ??? ??? ?bos.write(buff, 0, bytesRead); ?? ??? ??? ?} ?? ??? ?}catch(Exception e){ ?? ??? ??? ?e.printStackTrace(); ?? ??? ?}finally{ ?? ??? ??? ?if(bis!=null){ ?? ??? ??? ??? ?try { ?? ??? ??? ??? ??? ?bos.close(); ?? ??? ??? ??? ??? ?bis.close(); ?? ??? ??? ??? ?} catch (IOException e) { ?? ??? ??? ??? ??? ?e.printStackTrace(); ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?} ?? ?}
結(jié)論
URLConnection的響應(yīng)流InputStream在沒有處理之前就關(guān)閉connection會(huì)導(dǎo)致該輸入流信息為空,getInputStream()的available總是為0。
猜測(cè)disconnection可能執(zhí)行了輸入流的關(guān)閉操作了。response響應(yīng)頭如果不設(shè)置Content-Length,客戶端也能正確獲取到響應(yīng)文件的。
網(wǎng)上看到一種說法說如果將輸入流關(guān)閉后,則對(duì)應(yīng)的URLConnection也會(huì)自動(dòng)關(guān)閉了。
還有一個(gè)問題是如果Connection沒有執(zhí)行disconnect()操作,會(huì)有什么后果呢?
HttpURLConnection解決Feign報(bào)400問題
問題描述
項(xiàng)目中使用Feign組件遠(yuǎn)程調(diào)用問題記錄,本地代碼執(zhí)行正常,部署到服務(wù)器訪問調(diào)用不了遠(yuǎn)程接口,報(bào) feign.FeignException: status 400 reading,不太清楚是什么問題,分別用了httpclinet、resttemplate、feign,結(jié)果都失敗報(bào)同一個(gè)問題,明明本地運(yùn)行正常,線上就不正常了呢?
原因分析
網(wǎng)上查了很多報(bào)錯(cuò)的原因,但是都不符合,最后用了HttpURLConnection這個(gè)api 成功解決
解決方案
?? ?//post請(qǐng)求 ? ? public static <T> T doPost(String url, Object requestObj, Class<T> tClass) throws IOException { ? ? ? ? PrintWriter out = null; ? ? ? ? BufferedReader in = null; ? ? ? ? String result = ""; ? ? ? ? try { ? ? ? ? ? ? // 打開和URL之間的連接 ? ? ? ? ? ? HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); ? ? ? ? ? ? // 設(shè)置通用的請(qǐng)求屬性 ? ? ? ? ? ? conn.setRequestMethod("POST"); ? ? ? ? ? ? conn.setConnectTimeout(4 * 1000); ? ? ? ? ? ? conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); ? ? ? ? ? ? // 發(fā)送POST請(qǐng)求必須設(shè)置如下兩行 ? ? ? ? ? ? conn.setDoOutput(true); ? ? ? ? ? ? conn.setDoInput(true); ? ? ? ? ? ? // 獲取URLConnection對(duì)象對(duì)應(yīng)的輸出流 ? ? ? ? ? ? out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8")); ? ? ? ? ? ? out.println(JSON.toJSONString(requestObj)); ? ? ? ? ? ? // flush輸出流的緩沖 ? ? ? ? ? ? out.flush(); ? ? ? ? ? ? InputStream is = null; ? ? ? ? ? ? if (conn.getResponseCode() >= 400) { ? ? ? ? ? ? ? ? is = conn.getErrorStream(); ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? is = conn.getInputStream(); ? ? ? ? ? ? } ? ? ? ? ? ? // 定義BufferedReader輸入流來讀取URL的響應(yīng) ? ? ? ? ? ? in = new BufferedReader(new InputStreamReader(is,"utf-8")); ? ? ? ? ? ? String line; ? ? ? ? ? ? while ((line = in.readLine()) != null) { ? ? ? ? ? ? ? ? result += line; ? ? ? ? ? ? } ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? System.out.println("發(fā)送 POST 請(qǐng)求出現(xiàn)異常!" + e); ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? ? ? //使用finally塊來關(guān)閉輸出流、輸入流 ? ? ? ? finally { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? if (out != null) { ? ? ? ? ? ? ? ? ? ? out.close(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (in != null) { ? ? ? ? ? ? ? ? ? ? in.close(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } catch (IOException ex) { ? ? ? ? ? ? ? ? ex.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? log.info("流獲取的對(duì)象:---"+result); ? ? ? ? T t = JSON.parseObject(result, tClass); ? ? ? ? return t; ? ? } ?? ?//get請(qǐng)求 ? ? public static JSONObject useGetMethod(String get_url){ ? ? ? ? try { ? ? ? ? ? ? Map<String,Object> result = new HashMap<String,Object>(); ? ? ? ? ? ? JSONObject jsonObject=null; ? ? ? ? ? ? URL url = new URL(get_url); ? ? ? ? ? ? HttpURLConnection connection = (HttpURLConnection) url.openConnection(); ? ? ? ? ? ? connection.setRequestMethod("GET"); ? ? ? ? ? ? //設(shè)置連接遠(yuǎn)程服務(wù)器的超時(shí)時(shí)間 ? ? ? ? ? ? connection.setConnectTimeout(30000); ? ? ? ? ? ? //設(shè)置讀取遠(yuǎn)程返回的數(shù)據(jù)時(shí)間 ? ? ? ? ? ? connection.setReadTimeout(30000); ? ? ? ? ? ? connection.connect(); ? ? ? ? ? ? int responseCode = connection.getResponseCode(); ? ? ? ? ? ? if (responseCode == HttpURLConnection.HTTP_OK) { ? ? ? ? ? ? ? ? StringBuffer str = new StringBuffer(); ? ? ? ? ? ? ? ? InputStream in = connection.getInputStream(); ? ? ? ? ? ? ? ? BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8")); ? ? ? ? ? ? ? ? try{ ? ? ? ? ? ? ? ? ? ? String line = ""; ? ? ? ? ? ? ? ? ? ? while((line = br.readLine()) != null) { ? ? ? ? ? ? ? ? ? ? ? ? str.append(line); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } finally { ? ? ? ? ? ? ? ? ? ? br.close(); ? ? ? ? ? ? ? ? ? ? in.close(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? jsonObject = JSONObject.parseObject(str.toString()); // ? ? ? ? ? ? ? ?result.put("code", jsonObject.get("code")); // ? ? ? ? ? ? ? ?result.put("data", jsonObject.get("data")); ? ? ? ? ? ? }else{ // ? ? ? ? ? ? ? ?System.out.println("錯(cuò)誤狀態(tài)碼:"+responseCode); // ? ? ? ? ? ? ? ?result.put("code", responseCode); // ? ? ? ? ? ? ? ?result.put("message", "異常"); ? ? ? ? ? ? } ? ? ? ? ? ? connection.disconnect(); ? ? ? ? ? ? return jsonObject; ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? ? ? return null; ? ? }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Cloud Eureka服務(wù)治理的實(shí)現(xiàn)
服務(wù)治理是微服務(wù)框架中最為核心和基礎(chǔ)的模塊,它主要是用來實(shí)現(xiàn)各個(gè)微服務(wù)實(shí)例的自動(dòng)化注冊(cè)與發(fā)現(xiàn)。這篇文章主要介紹了Spring Cloud Eureka服務(wù)治理的實(shí)現(xiàn),感興趣的小伙伴們可以參考一下2018-06-06基于java實(shí)現(xiàn)具有時(shí)效性文件鏈接
這篇文章主要為大家詳細(xì)介紹了如何基于java實(shí)現(xiàn)具有時(shí)效性的文件鏈接,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下2023-12-12java創(chuàng)建一個(gè)類實(shí)現(xiàn)讀取一個(gè)文件中的每一行顯示出來
下面小編就為大家?guī)硪黄猨ava創(chuàng)建一個(gè)類實(shí)現(xiàn)讀取一個(gè)文件中的每一行顯示出來的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01mybatis?返回Map類型key默認(rèn)為大寫問題
這篇文章主要介紹了mybatis?返回Map類型key默認(rèn)為大寫問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11java中JSON字符串轉(zhuǎn)換為Map集合的兩種方法
本文主要介紹了java中JSON字符串轉(zhuǎn)換為Map集合,包含了兩種方法,這種需求可能涉及到從外部接口獲取數(shù)據(jù),或者在程序中處理配置信息等,感興趣的可以了解一下2024-07-07Mybatis-Plus中使用@DS注解動(dòng)態(tài)選擇數(shù)據(jù)源的源碼解讀
這篇文章主要介紹了Mybatis-Plus中使用@DS注解動(dòng)態(tài)選擇數(shù)據(jù)源的源碼解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07IntelliJ IDEA修改新建文件自動(dòng)生成注釋的user名
今天小編就為大家分享一篇關(guān)于IntelliJ IDEA修改新建文件自動(dòng)生成注釋的user名,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-10-10redisson特性及優(yōu)雅實(shí)現(xiàn)示例
這篇文章主要為大家介紹了redisson特性及優(yōu)雅實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11