HTTPURLConnection HTTP से HTTPS तक रीडायरेक्ट का पालन नहीं करता है


97

मुझे समझ नहीं आ रहा है कि HttpURLConnectionएक HTTP से HTTPS URL पर जावा पुनर्निर्देशित जावा का पालन क्यों नहीं करता है। मैं https://httpstat.us/ पर पेज प्राप्त करने के लिए निम्नलिखित कोड का उपयोग करता हूं :

import java.net.URL;
import java.net.HttpURLConnection;
import java.io.InputStream;

public class Tester {

    public static void main(String argv[]) throws Exception{
        InputStream is = null;

        try {
            String httpUrl = "http://httpstat.us/301";
            URL resourceUrl = new URL(httpUrl);
            HttpURLConnection conn = (HttpURLConnection)resourceUrl.openConnection();
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(15000);
            conn.connect();
            is = conn.getInputStream();
            System.out.println("Original URL: "+httpUrl);
            System.out.println("Connected to: "+conn.getURL());
            System.out.println("HTTP response code received: "+conn.getResponseCode());
            System.out.println("HTTP response message received: "+conn.getResponseMessage());
       } finally {
            if (is != null) is.close();
        }
    }
}

इस कार्यक्रम का आउटपुट है:

मूल URL: http://httpstat.us/301
से जुड़ा: http://httpstat.us/301
HTTP प्रतिक्रिया कोड प्राप्त: 301
HTTP प्रतिसाद संदेश प्राप्त हुआ: स्थायी रूप से ले जाया गया

Http://httpstat.us/301 के लिए एक अनुरोध निम्नलिखित (संक्षिप्त) प्रतिक्रिया देता है (जो बिल्कुल सही लगता है):!

HTTP/1.1 301 Moved Permanently
Cache-Control: private
Content-Length: 21
Content-Type: text/plain; charset=utf-8
Location: https://httpstat.us

दुर्भाग्य से, जावा HttpURLConnectionरीडायरेक्ट का पालन नहीं करता है!

ध्यान दें कि यदि आप मूल URL को HTTPS ( https://httpstat.us/301 ) में बदलते हैं , तो जावा अपेक्षित रूप से पुनर्निर्देशित होगा !?


नमस्ते, मैंने आपके प्रश्न को स्पष्टता के लिए संपादित किया और विशेष रूप से HTTPS को पुनर्निर्देशित करने के लिए समस्या का उल्लेख किया। इसके अलावा, मैंने बिट.ly डोमेन को एक अलग से बदल दिया है, क्योंकि बिट का उपयोग करें। प्रश्नों में ब्लैकलिस्ट किया गया है। आशा है कि आप बुरा नहीं मानेंगे, फिर से बेझिझक संपादित कर सकते हैं।
सेल्के

जवाबों:


119

रीडायरेक्ट का पालन केवल तभी किया जाता है जब वे एक ही प्रोटोकॉल का उपयोग करते हैं। (देखें विधि स्रोत में।) इस चेक निष्क्रिय करने के लिए कोई तरीका नहीं है।followRedirect()

भले ही हम जानते हैं कि यह HTTP प्रोटोकॉल दृष्टिकोण से HTTP दर्पण है, HTTPS सिर्फ कुछ अन्य, पूरी तरह से अलग, अज्ञात प्रोटोकॉल है। उपयोगकर्ता की स्वीकृति के बिना पुनर्निर्देशन का पालन करना असुरक्षित होगा।

उदाहरण के लिए, मान लें कि क्लाइंट प्रमाणीकरण स्वचालित रूप से करने के लिए एप्लिकेशन सेट है। उपयोगकर्ता अपेक्षा करता है कि वह गुमनाम रूप से सर्फिंग कर सकता है क्योंकि वह HTTP का उपयोग कर रहा है। लेकिन अगर उसका ग्राहक बिना पूछे HTTPS का पालन करता है, तो उसकी पहचान सर्वर से पता चलती है।


60
धन्यवाद। मुझे अभी-अभी पुष्टि मिली है: Bugs.sun.com/bugdatabase/view_bug.do?bug_id=20520571 । अर्थात्: "जावा नेटवर्किंग इंजीनियरों के बीच चर्चा के बाद, यह महसूस किया जाता है कि हमें स्वचालित रूप से एक प्रोटोकॉल से दूसरे में अप्रत्यक्ष रूप से पालन नहीं करना चाहिए, उदाहरण के लिए, http से https और vise versa, ऐसा करने से गंभीर सुरक्षा परिणाम हो सकते हैं। इस प्रकार फिक्स है। रीडायरेक्ट के लिए सर्वर प्रतिक्रियाओं को वापस करने के लिए। रिडायरेक्ट जानकारी के लिए रिस्पॉन्स कोड और स्थान हेडर फ़ील्ड मान की जाँच करें। यह रीडायरेक्ट का पालन करने के लिए एप्लिकेशन की जिम्मेदारी है। "
शेकेलीन

2
लेकिन क्या यह http से http या https से https तक रीडायरेक्ट होता है? वह भी गलत होगा। है ना?
सुदर्शन भट

7
@JoshuaDavis हाँ, यह केवल उसी प्रोटोकॉल पर पुनर्निर्देशित करता है। एक HttpURLConnectionअलग प्रोटोकॉल में रीडायरेक्ट का स्वचालित रूप से पालन नहीं होगा, भले ही रीडायरेक्ट झंडा सेट हो।
इरिकसन

8
जावा नेटवर्किंग इंजीनियर एक setFollowTransProtocol (असली) विकल्प की पेशकश कर सकता है क्योंकि अगर हमें इसकी आवश्यकता है तो हम इसे वैसे भी प्रोग्राम करेंगे। FYI करें वेब ब्राउजर, कर्ल और विंग और HTTP से HTTPS और इसके विपरीत तक रीडायरेक्ट का पालन कर सकते हैं।
सुपरकोबरा

18
कोई भी HTTPS पर ऑटो-लॉगिन सेट नहीं करता है और फिर HTTP को "अनाम" होने की उम्मीद करता है। वह निरर्थक है। HTTP से HTTPS तक (दूसरे तरीके से नहीं) रीडायरेक्ट का पालन करना पूरी तरह से सुरक्षित और सामान्य है। यह आमतौर पर खराब जावा एपीआई है।
ग्लेन मेनार्ड

54

HttpURLConnection द्वारा डिजाइन स्वचालित रूप से HTTPS (या इसके विपरीत) करने के लिए HTTP रीडायरेक्ट नहीं होंगे। पुनर्निर्देशन के बाद सुरक्षा के गंभीर परिणाम हो सकते हैं। SSL (इसलिए HTTPS) एक सत्र बनाता है जो उपयोगकर्ता के लिए अद्वितीय है। यह सत्र कई अनुरोधों के लिए पुन: उपयोग किया जा सकता है। इस प्रकार, सर्वर एकल व्यक्ति से किए गए सभी अनुरोधों को ट्रैक कर सकता है। यह पहचान का एक कमजोर रूप है और शोषक है। इसके अलावा, SSL हैंडशेक क्लाइंट के प्रमाणपत्र के लिए पूछ सकता है। यदि सर्वर पर भेजा जाता है, तो क्लाइंट की पहचान सर्वर को दी जाती है।

जैसा कि इरिकसन बताते हैं, मान लीजिए कि एप्लिकेशन को क्लाइंट प्रमाणीकरण स्वचालित रूप से करने के लिए सेट किया गया है। उपयोगकर्ता अपेक्षा करता है कि वह गुमनाम रूप से सर्फिंग कर सकता है क्योंकि वह HTTP का उपयोग कर रहा है। लेकिन अगर उसका ग्राहक बिना पूछे HTTPS का पालन करता है, तो उसकी पहचान सर्वर से पता चलती है।

प्रोग्रामर को यह सुनिश्चित करने के लिए अतिरिक्त कदम उठाने होंगे कि HTTP, HTTPS से रीडायरेक्ट करने से पहले क्रेडेंशियल, क्लाइंट सर्टिफिकेट या एसएसएल सेशन आईडी नहीं भेजा जाएगा। डिफ़ॉल्ट इन्हें भेजना है। यदि पुनर्निर्देशन उपयोगकर्ता को नुकसान पहुंचाता है, तो पुनर्निर्देशन का पालन न करें। यही कारण है कि स्वचालित रीडायरेक्ट समर्थित नहीं है।

उस समझ के साथ, यहां वह कोड है जो रीडायरेक्ट का पालन करेगा।

  URL resourceUrl, base, next;
  Map<String, Integer> visited;
  HttpURLConnection conn;
  String location;
  int times;

  ...
  visited = new HashMap<>();

  while (true)
  {
     times = visited.compute(url, (key, count) -> count == null ? 1 : count + 1);

     if (times > 3)
        throw new IOException("Stuck in redirect loop");

     resourceUrl = new URL(url);
     conn        = (HttpURLConnection) resourceUrl.openConnection();

     conn.setConnectTimeout(15000);
     conn.setReadTimeout(15000);
     conn.setInstanceFollowRedirects(false);   // Make the logic below easier to detect redirections
     conn.setRequestProperty("User-Agent", "Mozilla/5.0...");

     switch (conn.getResponseCode())
     {
        case HttpURLConnection.HTTP_MOVED_PERM:
        case HttpURLConnection.HTTP_MOVED_TEMP:
           location = conn.getHeaderField("Location");
           location = URLDecoder.decode(location, "UTF-8");
           base     = new URL(url);               
           next     = new URL(base, location);  // Deal with relative URLs
           url      = next.toExternalForm();
           continue;
     }

     break;
  }

  is = conn.openStream();
  ...

यह केवल एक समाधान है जो 1 से अधिक रीडायरेक्ट के लिए काम करता है। धन्यवाद!
रोजर एलियन

यह कई रीडायरेक्ट (HTTPS API -> HTTP -> HTTP छवि) के लिए खूबसूरती से काम करता है! एकदम सही सरल उपाय।
एरिकहोन

1
@ नथन - विवरण के लिए धन्यवाद, लेकिन मैं अभी भी इसे नहीं खरीदता। उदाहरण के लिए, यदि ग्राहक के नियंत्रण में है कि क्या कोई क्रेडेंशियल या क्लाइंट सेर्ट भेजे जाते हैं। यदि यह दर्द होता है, तो ऐसा न करें (इस मामले में, पुनर्निर्देश का पालन न करें)।
जूलियन रेसके

1
मैं केवल location = URLDecoder.decode(location...हिस्सा नहीं समझता । यह एक गैर-काम कर रहे एक काम कर रहे एन्कोडेड रिलेटिव पार्ट (स्पेस = + के साथ मेरे मामले में) को डिकोड करता है। बाद में मैंने उसे हटा दिया, यह मेरे लिए ठीक था।
नीक

@ नीक मुझे यकीन नहीं है कि आपको इसकी आवश्यकता नहीं है लेकिन मैं करता हूं।
नाथन

26

HttpURLConnection.setFollowRedirects(false)किसी भी मौके से कुछ कहा जाता है?

आप हमेशा कॉल कर सकते हैं

conn.setInstanceFollowRedirects(true);

यदि आप यह सुनिश्चित करना चाहते हैं कि आप ऐप के बाकी व्यवहार को प्रभावित न करें।


Ooo ... उस के बारे में नहीं जानता था ... अच्छा लगा ... मैं कक्षा में लगने वाला था कि इस तरह का तर्क था .... यह समझ में आता है कि यह एक ही जिम्मेदारी देने वाले शीर्ष लेख को वापस करेगा। प्रिंसिपल .... अब C # सवालों के जवाब देने के लिए वापस जाएँ: P [मैं मजाक कर रहा हूँ]
monksy

2
ध्यान दें कि setFollowRedirect () को क्लास में बुलाया जाना चाहिए, न कि किसी इंस्टेंस पर।
karlbecker_com 21

3
@dldnh: जबकि karlbecker_com setFollowRedirectsप्रकार पर कॉल करने के बारे में बिल्कुल सही था , setInstanceFollowRedirectsएक उदाहरण विधि है और इसे टाइप पर कॉल नहीं किया जा सकता है।
जॉन स्कीट

1
uggh, मैंने यह कैसे गलत किया। गलत संपादन के बारे में खेद है। रोलबैक करने की भी कोशिश की और यह भी सुनिश्चित नहीं किया कि मैं कैसे भी बोलूं।
dldnh

7

जैसा कि ऊपर आप में से कुछ ने उल्लेख किया है, setFollowRedirect और setInstanceFollowRedirects केवल तभी काम करते हैं जब पुनर्निर्देशित प्रोटोकॉल समान होता है। जैसे http से http और https से https।

setFolloRedirect वर्ग स्तर पर है और इसे url कनेक्शन के सभी उदाहरणों के लिए सेट करता है, जबकि setInstanceFollowRedirects केवल दिए गए उदाहरण के लिए है। इस तरह हम अलग-अलग उदाहरणों के लिए अलग-अलग व्यवहार कर सकते हैं।

मुझे यहाँ एक बहुत अच्छा उदाहरण मिला http://www.mkyong.com/java/java-httpurlconnection-follow-redirect-example/


2

एक और विकल्प अपाचे HttpCompords क्लाइंट का उपयोग किया जा सकता है :

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

नमूना कोड:

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("https://media-hearth.cursecdn.com/avatars/330/498/212.png");
CloseableHttpResponse response = httpclient.execute(httpget);
final HttpEntity entity = response.getEntity();
final InputStream is = entity.getContent();

-4

HTTPUrlConnection ऑब्जेक्ट की प्रतिक्रिया को संभालने के लिए ज़िम्मेदार नहीं है। यह अपेक्षित रूप से प्रदर्शन है, यह अनुरोधित URL की सामग्री को पकड़ लेता है। प्रतिक्रिया की व्याख्या करने के लिए यह कार्यक्षमता का उपयोगकर्ता है। यह विनिर्देश के बिना डेवलपर के इरादों को पढ़ने में सक्षम नहीं है।


7
इस मामले में यह सेट क्यों है। InFanceFollowRedirects? ))
शेकेलिन

मेरा अनुमान है कि यह बाद में जोड़ने के लिए सुझाया गया फीचर था, यह समझ में आता है .. मेरी टिप्पणी अधिक प्रतिबिंबित हुई थी ... वर्ग को वेब सामग्री को ले जाने और इसे वापस लाने के लिए डिज़ाइन किया गया है ... लोग चाहते हो सकते हैं गैर HTTP 200 संदेश प्राप्त करें।
21
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.