2014-04-17 10 views
6

मेरे पास एक स्प्रिंग एमवीसी एप्लिकेशन है जो किसी बाहरी सिस्टम से JSON स्ट्रिंग के रूप में HTTP अनुरोध प्राप्त करता है, और इसकी प्रतिक्रिया JSON स्ट्रिंग के समान ही लौटा दी जाती है। मेरा नियंत्रक सही ढंग से @RequestBody और @ResponseBody के साथ एनोटेटेड है और मेरे पास एकीकरण परीक्षण है जो वास्तव में यह सत्यापित करने के लिए अनुरोध भेजता है कि सब कुछ अपेक्षित काम करता है।स्प्रिंग एमवीसी: @RequestBody जब कोई सामग्री-प्रकार निर्दिष्ट नहीं किया गया है

हालांकि, जब मैं वास्तविक बाहरी प्रणाली के खिलाफ अपने आवेदन का परीक्षण करने गया, तो इसका उपयोग किया जाएगा, मैंने पाया कि आने वाले अनुरोध सामग्री प्रकार निर्दिष्ट नहीं करते हैं! यह पूरी तरह से त्रुटियों के निम्नलिखित प्रकार में स्प्रिंग और परिणाम confuses:

DEBUG [] 2014-04-17 13:33:13,471 AbstractHandlerExceptionResolver.java:132 resolveException - Resolving exception from handler [com.example.controller.M[email protected]]: org.springframework.web.HttpMediaTypeNotSupportedException: Cannot extract parameter (ValidationRequest request): no Content-Type found 

इसलिए, रूट करने के लिए MappingJacksonHttpMessageConverter के माध्यम से इस तरह का अनुरोध स्प्रिंग मजबूर करने के लिए एक रास्ता है, या तो किसी भी तरह एक कस्टम हैंडलर श्रृंखला का उपयोग करने के लिए मजबूर कर रहा स्प्रिंग या द्वारा किसी सामग्री-प्रकार को स्पष्ट रूप से सेट करने के लिए आने वाले अनुरोध को संशोधित करना?

मैं कुछ चीजें कोशिश की है:

  • विस्तार MappingJacksonHttpMessageConverter ताकि उसके canRead() और canWrite() तरीकों हमेशा सच लौट आते हैं। दुर्भाग्यवश, स्प्रिंग सामग्री प्रकार की कमी के कारण बाहर निकलने से पहले संदेश कन्वर्टर्स को देखने के बिंदु तक नहीं पहुंचती है।
  • मैन्युअल रूप से सामग्री प्रकार सेट करने के लिए इंटरसेप्टर या सर्वलेट फ़िल्टर का उपयोग करना। दुर्भाग्यवश, मैं इन विशेषताओं में से किसी एक के लिए वास्तव में आने वाले अनुरोध में बदलाव करने के लिए नए गुणों को स्थापित करने का कोई तरीका नहीं देख सकता।

किसी भी विचार की सराहना की जाती है।


नीचे टिप्पणी करने के लिए, मेरी @RequestMapping लगता है: ताकि JSON निर्दिष्ट करता है यहाँ कुछ भी नहीं है

@RequestMapping(value="/{service}") 
public @ResponseBody MyResponseObject(@PathVariable String service, @RequestBody MyRequestObject request) { 

, लेकिन किसी सामग्री प्रकार के बिना स्प्रिंग भी इमारत में एक चाकू लेने के लिए प्रकट नहीं होता है आने वाले अनुरोध से मेरा अनुरोध ऑब्जेक्ट (जो समझ में आता है, क्योंकि इसमें ऐसा करने के लिए पर्याप्त जानकारी नहीं है)।

और @ geoand की टिप्पणी के लिए, "आप एक सर्वलेट फ़िल्टर या स्प्रिंग इंटरसेप्टर में सामग्री-प्रकार http शीर्षलेख क्यों नहीं जोड़ सकते हैं", जवाब है "क्योंकि मैं गूंगा हूं और भूल गया कि सर्वलेट फ़िल्टर कैसे काम करते हैं"। यही वह दृष्टिकोण है जिसे मैंने अंततः समस्या को हल करने के लिए उपयोग किया था, जिसे मैं जल्द ही एक उत्तर के रूप में जोड़ दूंगा।

+0

यदि सामान्य सर्वलेट फ़िल्टर काम नहीं करते हैं, तो क्या आपने स्प्रिंग के अनुरोध इंटरसेप्टरफिल्टर की कोशिश की है? आपको अनुरोध को अवरुद्ध करने और वसंत के लिए अग्रेषित की गई एक नई प्रतिक्रिया लिखने की आवश्यकता होगी। –

+0

अपना @RequestMapping Code –

+0

जोड़ें मैपिंग में स्पष्ट रूप से कहा गया है कि आप केवल जेसन स्वीकार कर सकते हैं? है, आप Servlet Filter या Spring Interceptor में सामग्री-प्रकार http शीर्षलेख क्यों नहीं जोड़ सकते? – geoand

उत्तर

4

जब मैं इस सवाल से पूछा तो मैं थोड़ा सा गूंगा था क्योंकि मैं वसंत में सीधे आने वाले अनुरोध में हेरफेर करने के लिए एक रास्ता तलाश रहा था या अन्यथा स्पष्ट रूप से हैंडलर श्रृंखला को बताता हूं कि मैं हमेशा जेएसओएन के रूप में व्यवहार करने का अनुरोध चाहता हूं। एक बार जब मैंने थोड़ा सा सोचा, तो मुझे एहसास हुआ कि यह वही है जो सर्वलेट फ़िल्टर के लिए है।

public class ForcedContentTypeHttpServletRequestWrapper extends HttpServletRequestWrapper { 

    private static final Logger log = Logger.getLogger(ForcedContentTypeHttpServletRequestWrapper.class); 

    // this is the header to watch out for and what we should make sure it always resolves to. 
    private static final String CONTENT_TYPE_HEADER = "content-type"; 
    private static final String CONTENT_TYPE = "application/json"; 


    public ForcedContentTypeHttpServletRequestWrapper(HttpServletRequest request) { 
     super(request); 
    } 

    /** 
    * If content type is explicitly queried, return our hardcoded value 
    */ 
    @Override 
    public String getContentType() { 
     log.debug("Overriding request's content type of " + super.getContentType()); 
     return CONTENT_TYPE; 
    } 

    /** 
    * If we are being asked for the content-type header, always return JSON 
    */ 
    @Override 
    public String getHeader(String name) { 
     if (StringUtils.equalsIgnoreCase(name, CONTENT_TYPE_HEADER)) { 
      if (super.getHeader(name) == null) { 
       log.debug("Content type was not originally included in request"); 
      } 
      else { 
       log.debug("Overriding original content type from request: " + super.getHeader(name)); 
      } 
      log.debug("Returning hard-coded content type of " + CONTENT_TYPE); 
      return CONTENT_TYPE; 
     } 

     return super.getHeader(name); 
    } 

    /** 
    * When asked for the names of headers in the request, make sure "content-type" is always 
    * supplied. 
    */ 
    @SuppressWarnings({ "unchecked", "rawtypes" }) 
    @Override 
    public Enumeration getHeaderNames() { 

     ArrayList headerNames = Collections.list(super.getHeaderNames()); 
     if (headerNames.contains(CONTENT_TYPE_HEADER)) { 
      log.debug("content type already specified in request. Returning original request headers"); 
      return super.getHeaderNames(); 
     } 

     log.debug("Request did not specify content type. Adding it to the list of headers"); 
     headerNames.add(CONTENT_TYPE_HEADER); 
     return Collections.enumeration(headerNames); 
    } 

    /** 
    * If we are being asked for the content-type header, always return JSON 
    */ 
    @SuppressWarnings({ "rawtypes", "unchecked" }) 
    @Override 
    public Enumeration getHeaders(String name) { 
     if (StringUtils.equalsIgnoreCase(CONTENT_TYPE_HEADER, name)) { 
      if (super.getHeaders(name) == null) { 
       log.debug("Content type was not originally included in request"); 
      } 
      else { 
       log.debug("Overriding original content type from request: " + Collections.list(super.getHeaders(name))); 
      } 
      log.debug("Returning hard-coded content type of " + CONTENT_TYPE); 
      return Collections.enumeration(Arrays.asList(CONTENT_TYPE)); 
     } 

     return super.getHeaders(name); 
    } 

} 

मैं तो इस आवरण का उपयोग करने के लिए एक फिल्टर में इतनी तरह से रख::

सबसे पहले, मैं एक नया HttpServletRequestWrapper कि इस तरह दिखता है बनाया

public class ContentTypeFilter implements Filter { 

    /** 
    * @see Filter#destroy() 
    */ 
    @Override 
    public void destroy() { 
     // do nothing 
    } 

    /** 
    * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) 
    */ 
    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     ForcedContentTypeHttpServletRequestWrapper requestWrapper = new ForcedContentTypeHttpServletRequestWrapper((HttpServletRequest) request); 
     chain.doFilter(requestWrapper, response); 
    } 

    /** 
    * @see Filter#init(FilterConfig) 
    */ 
    @Override 
    public void init(FilterConfig fConfig) throws ServletException { 
     // do nothing 
    } 

} 

यह बिल्कुल बुलेट प्रूफ नहीं है, लेकिन यह एक स्रोत से सही तरीके से अनुरोध संभालता है कि इस एप्लिकेशन को वास्तव में परवाह है।

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