2012-08-26 13 views
17

मुझे अपने स्प्रिंग सर्वलेट में एक HttpServletRequest अनुरोध मिला है कि मैं एक अलग सर्वर पर AS-IS (यानी POST या GET सामग्री) को अग्रेषित करना चाहता हूं।फॉरवर्ड HttpServletRequest एक अलग सर्वर

वसंत ढांचे का उपयोग करके इसे करने का सबसे अच्छा तरीका क्या होगा?

क्या मुझे सभी जानकारी पकड़ने और HTTPUrlConnection बनाने की आवश्यकता है? या क्या कोई आसान तरीका है?

उत्तर

4

दुर्भाग्य से ऐसा करने का कोई आसान तरीका नहीं है। मूल रूप से आप अनुरोध फिर से संगठित करने, सहित होगा:

  • सही HTTP विधि
  • अनुरोध पैरामीटर
  • अनुरोध हेडर (मनमाने ढंग से उपयोगकर्ता एजेंट स्थापित करने के लिए अनुमति नहीं है HTTPUrlConnection, "Java/1.*" हमेशा जोड़ दिया जाता है, आप HttpClient की आवश्यकता होगी)
  • शरीर

बहुत काम है यही कारण है, के लिए यह ऐसे प्रत्येक प्रॉक्सी कॉल के बाद बड़े पैमाने अपने मीटर पर एक धागा को घेरता है नहीं होगा का उल्लेख नहीं achine।

मेरी सलाह: कच्चे सॉकेट या का उपयोग करें और निम्नतम स्तर पर HTTP प्रोटोकॉल को अवरुद्ध करें, बस कुछ मूल्यों को प्रतिस्थापित करें (जैसे Host शीर्षलेख) पर। क्या आप अधिक संदर्भ प्रदान कर सकते हैं, तो आपको इसकी आवश्यकता क्यों है?

+0

मुझे क्लाइंट, इंटरमीडिएट सर्वर और कुछ मुख्य सर्वर मिल गए। क्लाइंट केवल मध्यवर्ती सर्वर से बात करता है जो सर्वर पर अपनी कॉल भेजता है। सर्वर इंटरमीडिएट सर्वर को प्रतिक्रिया देता है, जिसे वह तब संसाधित करता है, और उसके बाद ग्राहक को प्रतिक्रिया देता है। – user1144031

+0

अनुरोध हेडर (3) और बॉडी (4) को प्रतिलिपि पैरामीटर (2) की प्रतिलिपि बनाने के लिए तैयार नहीं करना चाहिए (क्योंकि पोस्ट पैरामीटर अनुरोध निकाय का हिस्सा हैं, क्योंकि वे यूआरएल का हिस्सा होंगे)? यदि मैं दोनों चरणों को निष्पादित करता हूं तो यह reduntant (http अनुरोध में) होगा – mickeymoon

10

आप इस तरह से अग्रेषण करते करना चाहिए कि क्या एक तरफ की चर्चाएँ, यहाँ है कैसे मैंने किया:

package com.example.servlets; 

import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.Enumeration; 

import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import com.example.servlets.GlobalConstants; 

@SuppressWarnings("serial") 
public class ForwardServlet extends HttpServlet { 

    @Override 
    public void doGet(HttpServletRequest req, HttpServletResponse resp) { 
     forwardRequest("GET", req, resp); 
    } 

    @Override 
    public void doPost(HttpServletRequest req, HttpServletResponse resp) { 
     forwardRequest("POST", req, resp); 
    } 

    private void forwardRequest(String method, HttpServletRequest req, HttpServletResponse resp) { 
     final boolean hasoutbody = (method.equals("POST")); 

     try { 
      final URL url = new URL(GlobalConstants.CLIENT_BACKEND_HTTPS // no trailing slash 
        + req.getRequestURI() 
        + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); 
      HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
      conn.setRequestMethod(method); 

      final Enumeration<String> headers = req.getHeaderNames(); 
      while (headers.hasMoreElements()) { 
       final String header = headers.nextElement(); 
       final Enumeration<String> values = req.getHeaders(header); 
       while (values.hasMoreElements()) { 
        final String value = values.nextElement(); 
        conn.addRequestProperty(header, value); 
       } 
      } 

      //conn.setFollowRedirects(false); // throws AccessDenied exception 
      conn.setUseCaches(false); 
      conn.setDoInput(true); 
      conn.setDoOutput(hasoutbody); 
      conn.connect(); 

      final byte[] buffer = new byte[16384]; 
      while (hasoutbody) { 
       final int read = req.getInputStream().read(buffer); 
       if (read <= 0) break; 
       conn.getOutputStream().write(buffer, 0, read); 
      } 

      resp.setStatus(conn.getResponseCode()); 
      for (int i = 0; ; ++i) { 
       final String header = conn.getHeaderFieldKey(i); 
       if (header == null) break; 
       final String value = conn.getHeaderField(i); 
       resp.setHeader(header, value); 
      } 

      while (true) { 
       final int read = conn.getInputStream().read(buffer); 
       if (read <= 0) break; 
       resp.getOutputStream().write(buffer, 0, read); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
      // pass 
     } 
    } 
} 

जाहिर है इस से निपटने और जैसे त्रुटि के संबंध में काम का एक सा इस्तेमाल कर सकते हैं लेकिन यह कार्यात्मक था । मैंने इसका उपयोग करना बंद कर दिया, हालांकि, क्योंकि मेरे मामले में कुकीज, ऑथ इत्यादि से दो अलग-अलग डोमेनों में निपटने के लिए सीधे CLIENT_BACKEND पर कॉल करना आसान था।

2

मुझे भी ऐसा करने की आवश्यकता है, और वसंत नियंत्रकों और रेस्ट टेम्पलेट के साथ कुछ गैर इष्टतम के बाद, मुझे एक बेहतर समाधान मिला: Smiley's HTTP Proxy Servlet। लाभ यह है कि यह वास्तव में एएस-आईएस प्रॉक्सी कर रहा है, जैसे अपाचे के mod_proxy, और यह स्मृति में पूर्ण अनुरोध/प्रतिक्रिया को कैश किए बिना स्ट्रीमिंग तरीके से करता है।

बस, आप उस पथ पर एक नया सर्वलेट पंजीकृत करते हैं जिसे आप किसी अन्य सर्वर पर प्रॉक्सी करना चाहते हैं, और यह सर्वलेट लक्ष्य होस्ट को एक init पैरामीटर के रूप में दें। यदि आप एक web.xml के साथ एक पारंपरिक वेब अनुप्रयोग का उपयोग कर रहे हैं, तो आप तो वह ऐसा कॉन्फ़िगर कर सकते हैं:

<servlet> 
    <servlet-name>proxy</servlet-name> 
    <servlet-class>org.mitre.dsmiley.httpproxy.ProxyServlet</servlet-class> 
    <init-param> 
     <param-name>targetUri</param-name> 
     <param-value>http://target.uri/target.path</param-value> 
    </init-param> 
</servlet> 
<servlet-mapping> 
    <servlet-name>proxy</servlet-name> 
    <url-pattern>/mapping-path/*</url-pattern> 
</servlet-mapping> 

या, ज़ाहिर है, आप annotation config साथ जा सकते हैं।

आप स्प्रिंग बूट का उपयोग कर रहे हैं, तो यह और भी आसान है: आप केवल आवश्यक विन्यास के साथ, प्रकार ServletRegistrationBean की एक सेम बनाने की जरूरत:

@Bean 
public ServletRegistrationBean proxyServletRegistrationBean() { 
    ServletRegistrationBean bean = new ServletRegistrationBean(
      new ProxyServlet(), "/mapping-path/*"); 
    bean.addInitParameter("targetUri", "http://target.uri/target.path"); 
    return bean; 
} 

इस तरह, आप भी वसंत गुणों का उपयोग कर सकते हैं कि पर्यावरण में उपलब्ध हैं।

आप कक्षा ProxyServlet भी बढ़ा सकते हैं और यदि आपको आवश्यकता हो तो अनुरोध/प्रतिक्रिया शीर्षलेख इत्यादि को अनुकूलित करने के लिए अपने तरीकों को ओवरराइड कर सकते हैं।

अद्यतन: कुछ समय के लिए स्माइली के प्रॉक्सी सर्वलेट का उपयोग करने के बाद, हमारे पास कुछ समय-समय पर समस्याएं थीं, यह विश्वसनीय रूप से काम नहीं कर रही थी। Netflix से Zuul पर स्विच किया गया, उसके बाद कोई समस्या नहीं थी। स्प्रिंग बूट के साथ इसे कॉन्फ़िगर करने पर एक ट्यूटोरियल this link पर पाया जा सकता है।

संबंधित मुद्दे