1. 程式人生 > >nginx rewrite(301)重定向之後無法正常請求的解決方案

nginx rewrite(301)重定向之後無法正常請求的解決方案

前言

前面通過騰訊雲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的重定向,從而不必要修改客戶端請求時的程式碼即可完成這塊的動作,如果有那位大牛知道怎麼做,煩請留言告知,萬分感謝!