前言
前面通過騰訊雲ssl證書實現了https的請求,如果想簡單瞭解可參考如何添加SSL證書實現https請求;爲了滿足之前http請求不受影響,在nginx上面不僅配置了https的443端口的監聽,同時監聽了80端口。通過瀏覽器測試確實是沒有問題,但是在寫代碼時,java代碼發起get,post請求的時候,出現了“301 Moved Permanently”的錯誤;網上也沒有搜索到好的解決方案,經過一下午的分析,找到了一個突破口,但是總覺得並不是一個好的方式,再此分享一下,如果有人能有更好的方式解決此問題,煩請告知一下。
問題追蹤
獲取HeaderFields
當我們通過一個http的地址得到一個URLConnection連接之後;通過getHeaderFields()獲取這個連接的響應頭,代碼如下:String urlName = url + "?" + param; URL realUrl = new URL(urlName); // 打開和URL之間的連接 URLConnection conn = realUrl.openConnection(); Map<String, List<String>> map = conn.getHeaderFields(); // 遍歷所有的響應頭字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key).get(0)); }
如果是http的請求我們可以看到如下信息:
這裏給出了新的重定向後的地址;如果是https的請求,就不會出現這個Location字段;並且能正常請求成功,效果如下:
瀏覽器能正常請求個人認爲是在出現錯誤之後,瀏覽器發現存在新地址Location字段;就取到了新地址重新發起了一次新的請求從而實現了正常的響應。
解決方案
既然上面說道瀏覽器檢測到Location字段,拿到新的地址重新發起了一次新的請求,那麼代碼也同樣是可以這麼實現的,因此調整了代碼,寫了如下工具類:import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.URL; import java.net.URLConnection; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.commons.httpclient.util.HttpURLConnection; import org.apache.http.ParseException; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; public class HttpClientUtil { /** * 向指定URL發送GET方法的請求 * * @param url * 發送請求的URL * @param param * 請求參數,請求參數應該是name1=value1&name2=value2的形式。 * @return URL所代表遠程資源的響應 */ public static String sendGet(String url, String param) { String result = ""; BufferedReader in = null; try { String urlName = url + "?" + param; URL realUrl = new URL(urlName); // 打開和URL之間的連接 URLConnection conn = realUrl.openConnection(); String newUrl = urlName; Map<String, List<String>> map = conn.getHeaderFields(); // 遍歷所有的響應頭字段 for (String key : map.keySet()) { //如果發現有重定向了新的地址 if ("Location".equals(key)) { //獲取新地址 newUrl = map.get(key).get(0) + "?" + param; break; } } // 重新實例化url對象 realUrl = new URL(newUrl); // 重新打開和URL之間的連接 conn = realUrl.openConnection(); // 設置通用的請求屬性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("Accept-Charset", "UTF-8"); conn.setRequestProperty("contentType", "UTF-8"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); conn.setRequestProperty("Accept-Language", Locale.getDefault().toString()); // 建立實際的連接 conn.connect(); // 定義BufferedReader輸入流來讀取URL的響應 in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("發送GET請求出現異常!" + e); e.printStackTrace(); } // 使用finally塊來關閉輸入流 finally { try { if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; } /** * post請求 */ public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 打開和URL之間的連 ? URLConnection conn = realUrl.openConnection(); Map<String, List<String>> map = conn.getHeaderFields(); // 遍歷所有的響應頭字段 String newUrl = url; for (String key : map.keySet()) { //如果發現有重定向了新的地址 if ("Location".equals(key)) { //獲取新地址 newUrl = map.get(key).get(0); break; } } realUrl = new URL(newUrl); // 打開和URL之間的連接 conn = realUrl.openConnection(); // 設置通用的請求屬 ? conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("Accept-Charset", "UTF-8"); conn.setRequestProperty("contentType", "UTF-8"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded;charset=UTF-8"); conn.setRequestProperty("Accept-Language", Locale.getDefault().toString()); // 發起POST請求必須設置如下兩行 conn.setDoOutput(true); conn.setDoInput(true); // 獲取URLConnection對象對應的輸出流 out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8")); // 發 ?請求參數 out.print(param); // flush輸出流的緩衝 out.flush(); // 定義BufferedReader輸入流來讀取URL的響應 in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { e.printStackTrace(); } // 使用finally塊來關閉輸出流 ?輸入 ? finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; } }
總結
雖說通過調整客戶端請求的時候通過調整,實現重定向的功能,但是我認爲這並不是最好的解決方式;個人是希望能通過nginx那塊的配置實現http到https的重定向,從而不必要修改客戶端請求時的代碼即可完成這塊的動作,如果有那位大牛知道怎麼做,煩請留言告知,萬分感謝!