HttpServletResponse.getOutputStream () /। GetWriter () पर एक .close () को कॉल करना चाहिए?


96

जावा सर्वलेट्स में, कोई भी प्रतिक्रिया निकाय के माध्यम से response.getOutputStream()या तक पहुँच सकता है response.getWriter()। क्या इसे लिखे जाने के बाद .close()इस पर कॉल किया जाना चाहिए OutputStream?

एक ओर, हमेशा बंद करने के लिए ब्लोचियन उद्बोधन होता है OutputStream। दूसरी ओर, मुझे नहीं लगता कि इस मामले में एक अंतर्निहित संसाधन है जिसे बंद करने की आवश्यकता है। लगातार कनेक्शन और इस तरह की चीजों की अनुमति देने के लिए, सॉकेट्स के उद्घाटन / समापन को HTTP स्तर पर प्रबंधित किया जाता है।


आपको इस बारे में अनुमान लगाने के लिए आमंत्रित नहीं किया जाता है कि क्या कोई अंतर्निहित संसाधन बंद होना है। यदि कार्यान्वयनकर्ता ऐसा सोचता है, या ऐसा जानता है, तो वह close()कुछ भी नहीं प्रदान करेगा । क्या आप क्या करना चाहिए करीब हर closeable संसाधन है।
लोर्ने का मार्किस

1
यहां तक ​​कि अगर आपका कोड इसे नहीं खोला है? मुझे ऐसा नहीं लगता ...
स्टीवन हुआविग

जवाबों:


93

आम तौर पर आपको धारा को बंद नहीं करना चाहिए। सर्वलेट अनुरोध जीवन-चक्र के भाग के रूप में सर्वलेट समाप्त होने के बाद सर्वलेट कंटेनर धारा को स्वचालित रूप से बंद कर देगा।

उदाहरण के लिए, यदि आपने स्ट्रीम को बंद कर दिया है तो फ़िल्टर उपलब्ध होने पर यह उपलब्ध नहीं होगा ।

यह सब कहने के बाद, यदि आप इसे बंद करते हैं तो कुछ भी बुरा नहीं होगा जब तक आप इसे फिर से उपयोग करने की कोशिश नहीं करते हैं।

संपादित करें: एक और फिल्टर लिंक

EDIT2: adrian.tarau सही है कि यदि आप सर्वलेट के बाद प्रतिक्रिया को बदलना चाहते हैं तो आपको HttpServletResponseWrapper का विस्तार करने वाला एक आवरण बनाना चाहिए और आउटपुट को बफर करना चाहिए। यह आउटपुट को क्लाइंट तक सीधे जाने से रोकने के लिए है, लेकिन अगर यह इस अंश (जोर मेरा) के अनुसार, सर्वलेट स्ट्रीम को बंद कर देता है, तो आपको सुरक्षा प्रदान करने की अनुमति देता है:

एक फ़िल्टर जो एक प्रतिक्रिया को संशोधित करता है, उसे ग्राहक को वापस करने से पहले आमतौर पर प्रतिक्रिया पर कब्जा करना चाहिए । ऐसा करने का तरीका सर्वलेट पास करना है जो प्रतिक्रिया को स्टैंड-इन स्ट्रीम उत्पन्न करता है। स्टैंड-इन स्ट्रीम सर्वलेट को मूल प्रतिक्रिया स्ट्रीम को बंद करने से रोकता है जब यह पूरा हो जाता है और फ़िल्टर को सर्वलेट की प्रतिक्रिया को संशोधित करने की अनुमति देता है।

लेख

कोई भी उस आधिकारिक सन लेख से अनुमान लगा सकता है कि OutputStreamएक सर्वलेट से बंद करना एक ऐसी घटना है जो एक सामान्य घटना है, लेकिन अनिवार्य नहीं है।


2
यह सही है। एक बात का ध्यान रखें कि कुछ मामलों में आपको स्ट्रीम को फ्लश करने की आवश्यकता हो सकती है, और यह पूरी तरह से स्वीकार्य है।
११:४५ बजे टुल्लू जू २१'०

1
लेखक को बंद करने का एक और दुष्प्रभाव है। इसके बंद होने के बाद आप response.setStatus के द्वारा भी स्टेटस कोड सेट नहीं कर पाएंगे।
che javara

1
इस सलाह का पालन करें। यह आपको बहुत दर्द से बचाएगा। जब तक आप यह नहीं जानते कि मैं क्या कर रहा हूं, तब तक मैं नहीं जाऊंगा () आप कंटेनर को बफ़र करने देना चाहिए।
२१:११ बजे हल ५००००

75

उनमें से सामान्य नियम यह है: यदि आपने धारा खोली है, तो आपको इसे बंद कर देना चाहिए। यदि आपने नहीं किया, तो आपको नहीं करना चाहिए। सुनिश्चित करें कि कोड सममित है।

के मामले में HttpServletResponse, यह थोड़ा कम स्पष्ट कट है, क्योंकि यह स्पष्ट नहीं है यदि कॉलिंग getOutputStream()एक ऑपरेशन है जो स्ट्रीम को खोलता है। जावदोक सिर्फ यह कहता है कि यह " Returns a ServletOutputStream"; इसी तरह के लिए getWriter()। किसी भी तरह, जो स्पष्ट है वह HttpServletResponseधारा / लेखक का "मालिक" है, और यह (या कंटेनर) इसे फिर से बंद करने के लिए जिम्मेदार है।

तो अपने प्रश्न का उत्तर देने के लिए - नहीं, आपको इस मामले में धारा को बंद नहीं करना चाहिए। कंटेनर को ऐसा करना चाहिए, और यदि आप इससे पहले वहां पहुंचते हैं, तो आप अपने आवेदन में सूक्ष्म कीड़े शुरू करने का जोखिम उठाते हैं।


मैं इस जवाब से सहमत हूं, आप ServletResponse.flushBuffer () देखें: docs.oracle.com/javaee/1.4/api/javax/servlet/…
साइबर संन्यासी

14
"यदि आपने धारा खोली है, तो आपको इसे बंद कर देना चाहिए। यदि आपने नहीं किया, तो आपको नहीं करना चाहिए" --- अच्छी तरह से कहा
श्रीकांत रेड्डी लिंगला

2
ऐसा लगता है कि स्कूल बोर्ड पर पोस्ट किए गए वाक्य "यदि आप इसे खोलते हैं, तो इसे बंद कर दें। यदि आप इसे चालू करते हैं, तो इसे बंद कर दें। यदि आप इसे अनलॉक करते हैं, तो इसे लॉक कर दें। [...]"
रिकार्डो

Iv ने देखा कि मैं अपने कोड में जल्दी स्ट्रीम का उपयोग करता हूं और फिर कभी नहीं, क्लाइंट पूरे सर्वलेट को निष्पादित करने के लिए प्रतीक्षा करता है, लेकिन जब मैं close()स्ट्रीम के साथ किया जाता हूं , तो क्लाइंट तुरंत वापस आ जाता है और बाकी सर्वलेट निष्पादित करना जारी रखता है। नहीं है कि फिर जवाब थोड़ा और अधिक सापेक्ष बना? एक निश्चित हाँ या ना के
विपरीत

"यदि आपने स्ट्रीम को खोला है, तो आपको इसे बंद कर देना चाहिए। यदि आपने नहीं किया, तो आपको नहीं करना चाहिए। सुनिश्चित करें कि कोड सममित है।" - तो क्या हुआ अगर आप एक और स्ट्रीम बनाते हैं जो इस स्ट्रीम को लपेटता है? इस मामले में सममित रहने के लिए मुश्किल है क्योंकि बाहरी धारा को बंद करने से आमतौर पर नेस्टेड को बंद कर दिया जाएगा।
स्टेनिबोट

5

यदि कोई मौका है तो फ़िल्टर को 'शामिल' संसाधन पर बुलाया जा सकता है, तो आपको निश्चित रूप से स्ट्रीम को बंद नहीं करना चाहिए । यह एक 'स्ट्रीम बंद' अपवाद के साथ संसाधन सहित विफल हो जाएगा।


इस टिप्पणी को जोड़ने के लिए धन्यवाद। प्रफुल्लित रूप से मैं अभी भी समस्या से थोड़ा जूझ रहा हूं - अभी मैंने देखा कि नेटबीन्स के सर्वलेट टेम्प्लेट में आउटपुट स्ट्रीम को बंद करने के लिए कोड शामिल है ...
स्टीवन हुआविग

4

जब आप getOutputStream () का आह्वान करते हैं तो आपको स्ट्रीम बंद कर देनी चाहिए, जब आप आम तौर पर इसका उपयोग करते हैं और इसे बंद करने का प्रयास नहीं करते हैं, तो स्ट्रीम आपको एक पैरामीटर के रूप में पारित कर देता है। सर्वलेट एपीआई यह नहीं बताता है कि अगर आउटपुट स्ट्रीम को बंद किया जा सकता है या बंद नहीं किया जाना चाहिए, तो इस स्थिति में आप सुरक्षित रूप से स्ट्रीम को बंद कर सकते हैं, यदि कोई भी कंटेनर स्ट्रीम को बंद नहीं करता है तो धारा को बंद करने का ख्याल रखता है।

यहां जेटी में करीब () विधि है, वे धारा को बंद कर देते हैं यदि यह बंद नहीं है।

public void close() throws IOException
    {
        if (_closed)
            return;

        if (!isIncluding() && !_generator.isCommitted())
            commitResponse(HttpGenerator.LAST);
        else
            flushResponse();

        super.close();
    }

फ़िल्टर के डेवलपर के रूप में भी आपको यह नहीं मानना ​​चाहिए कि आउटपुटस्ट्रीम बंद नहीं है, आपको हमेशा एक और आउटपुटस्ट्रीम को पास करना चाहिए यदि आप सर्वलेट के काम के बाद सामग्री को बदलना चाहते हैं।

संपादित करें: मैं हमेशा स्ट्रीम बंद कर रहा हूं और मुझे टॉमकैट / जेट्टी के साथ कोई समस्या नहीं थी। मुझे नहीं लगता कि आपको किसी भी कंटेनर, पुराने या नए के साथ कोई समस्या होनी चाहिए।


4
"आपको स्ट्रीम को बंद करना चाहिए, कोड क्लीनर है ..." - मेरे लिए, .close () के साथ कोड बिना कोड के कम साफ दिखता है, खासकर अगर .close () अनावश्यक है - जो कि यह सवाल है। निर्धारित करने का प्रयास।
स्टीवन हुआविग

1
हां, लेकिन सुंदरता के बाद आता है :) वैसे भी, एपीआई स्पष्ट नहीं है मैं इसे बंद करना पसंद करूंगा, कोड सुसंगत दिखता है, एक बार जब आप आउटपुटस्ट्रीम को अनुरोध करते हैं तो आपको इसे बंद करना चाहिए जब तक कि एपीआई यह नहीं कहता कि "इसे बंद न करें"।
adrian.tarau

मुझे नहीं लगता कि अपने स्वयं के कोड में आउटपुट स्ट्रीम को बंद करना एक अच्छा अभ्यास है। यह कंटेनर का काम है।
जिमहॉकिन्स

get * स्ट्रीम नहीं बनाता है, यह निर्माता नहीं है। आपको इसे बंद नहीं करना चाहिए, कंटेनर को इसे करना चाहिए।
dmatej

3

समापन के खिलाफ एक और तर्क OutputStream। इस सर्वलेट को देखो। यह एक अपवाद फेंकता है। JSP में अपवाद को त्रुटि JSP में मैप किया गया है:

package ser;

import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet(name = "Erroneous", urlPatterns = {"/Erroneous"})
public class Erroneous extends HttpServlet {

  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setContentType("text/html;charset=UTF-8");
    PrintWriter out = resp.getWriter();
    try {
      throw new IOException("An error");
    } finally {
//      out.close();
    }
  }
}

Web.xml फ़ाइल में शामिल हैं:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <error-page>
        <exception-type>java.io.IOException</exception-type>
        <location>/error.jsp</location>
    </error-page>
</web-app>

और त्रुटि .jsp:

<%@page contentType="text/html" pageEncoding="UTF-8" isErrorPage="true"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Error Page</title>
    </head>
    <body>
        <h1><%= exception.getMessage()%></h1>
    </body>
</html>

जब आप /Erroneousब्राउज़र में लोड करते हैं तो आप "एक त्रुटि" प्रदर्शित करते हुए त्रुटि पृष्ठ देखते हैं। लेकिन अगर आप अन-कमेंट करते हैंout.close() ऊपर दिए गए सर्वलेट में लाइन को , तो deeploy de application, और पुनः लोड करें /Erroneousआपको ब्राउज़र में कुछ भी दिखाई नहीं देगा। वास्तव में क्या हो रहा है, इसके बारे में मेरे पास कोई सुराग नहीं है, लेकिन मुझे लगता है कि out.close()त्रुटि से निपटने से रोकता है।

टॉमकैट 7.0.50 के साथ परीक्षण किया गया, नेटबीन 7.4 का उपयोग करके जावा ईई 6।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.