Results 1 to 3 of 3

Thread: specifying a different Content-Type header for @ResponseBody and JSONP output

  1. #1
    Join Date
    Nov 2009
    Location
    Montreal, Quebec
    Posts
    398

    Default specifying a different Content-Type header for @ResponseBody and JSONP output

    I have a method in my controller annotated with @ResponseBody which produces JSON output. I've written a servlet filter (suggested by Jeremy Grelle) that gets called when requests are made ending in *.json. That filter also checks to see if there is a "callback" parameter with the request. If there is, it wraps the response output with the callback method.

    The small issue I'm having now though is that the response still has a Content-Type of application/json, but it should be application/javascript. I've tried changing it in my filter before the chain.doFilter call, but my browser still shows a Content-Type header of application/json on the response.

    This is my doFilter method:

    Code:
    @SuppressWarnings("unchecked")
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {		
    	HttpServletRequest httpRequest = (HttpServletRequest) request;
    	HttpServletResponse httpResponse = (HttpServletResponse) response;
    	
    	Map<String, String[]> parms = httpRequest.getParameterMap();
    	
    	/*
    	 * Check if parameter map contains a "callback" key indicating
    	 * a JSONP request is being made.  If parameter map does not contain
    	 * a "callback" key, then filter will proceed without wrapping
    	 * JSON output with the callback method.
    	 */
    	if(parms.containsKey("callback")) {
    		if(log.isDebugEnabled())
    			log.debug("Wrapping response with JSONP callback '" + parms.get("callback")[0] + "'");
    		
    		OutputStream out = httpResponse.getOutputStream();
    		
    		GenericResponseWrapper wrapper = new GenericResponseWrapper(httpResponse);
    		wrapper.setContentType("application/javascript;charset=UTF-8");
    		
    		chain.doFilter(request, wrapper);
    		
    		out.write(new String(parms.get("callback")[0] + "(").getBytes());
    		out.write(wrapper.getData());
    		out.write(new String(");").getBytes());
    		out.close();
    	} else {
    		chain.doFilter(request, response);
    	}
    }
    Last edited by pgrimard; Jul 23rd, 2010 at 08:07 AM.

  2. #2
    Join Date
    Nov 2009
    Location
    Montreal, Quebec
    Posts
    398

    Default

    I'm wondering if I can accomplish what I need by explicitly specifying a MappingJacksonJsonView. I'm not sure if I can though as the default content type for it is application/json. I don't want to set the default to application/javascript because I may not always be doing JSONP requests. Some might be simple JSON requests, so I don't think setting that up will work, although I might be wrong.

  3. #3
    Join Date
    Nov 2009
    Location
    Montreal, Quebec
    Posts
    398

    Talking Sovled!

    Turns out it was as simple as changing where I was setting the content type on my response wrapper. In my initial code, I was setting the content type to "application/javascript;charset=UTF-8" right after having created the wrapped response, but before the chain.doFilter. After running in debug a few times, I determined that I was indeed successfully setting the content type, but the following call to chain.doFilter was changing it to "application/json;charset=UTF-8" thereby overwriting what I had set.

    Moving my "wrapper.setContentType" call to after the "chain.doFilter" call permitted my filter to overwrite the "application/json" content type with "application/javascript" content type. I also experimented with other locations to put my line of code. Placing my line of code after out.close() resulted in the content type not being overwritten, so it needed to be ahead of out.close().

    This is the resulting doFilter method:

    Code:
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		HttpServletRequest httpRequest = (HttpServletRequest) request;
    		HttpServletResponse httpResponse = (HttpServletResponse) response;
    		
    		Map<String, String[]> parms = httpRequest.getParameterMap();
    		
    		/*
    		 * Check if parameter map contains a "callback" key indicating
    		 * a JSONP request is being made.  If parameter map does not contain
    		 * a "callback" key, then filter will proceed without wrapping
    		 * JSON output with the callback method.
    		 */
    		if(parms.containsKey("callback")) {
    			
    			if(log.isDebugEnabled())
    				log.debug("Wrapping response with JSONP callback '" + parms.get("callback")[0] + "'");
    			
    			OutputStream out = httpResponse.getOutputStream();
    			
    			GenericResponseWrapper wrapper = new GenericResponseWrapper(httpResponse);
    			
    			chain.doFilter(request, wrapper);
    			
    			out.write(new String(parms.get("callback")[0] + "(").getBytes());
    			out.write(wrapper.getData());
    			out.write(new String(");").getBytes());
    			
    			wrapper.setContentType("application/javascript;charset=UTF-8");
    			
    			out.close();
    		} else {
    			chain.doFilter(request, response);
    		}
    	}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •