Announcement Announcement Module
Collapse
No announcement yet.
Roo 1.2.2 web mvc json controller behaves differently in browsers FF and IE Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Roo 1.2.2 web mvc json controller behaves differently in browsers FF and IE

    Hello,

    Background:
    We've successfully upgraded our web project from Spring Framework 3.0.5 to 3.1.0 and from Roo 1.1.5 to 1.2.2.
    We tested our app in Firefox, it worked fine. Just a quick note about the web mvc controllers, we use both the standard non-Json controllers and the Json controllers (mostly AJAX calls where we will set request headers="Accept=application/json".

    Issue:
    When we tested our app in IE, we got so many problems (which used to work just fine).
    For example: when I clicked on "list objects" menu link, it supposed to call a standard non-Json controller method to list objects in a CRUD table (based on Spring Roo tag library); instead, it actually prompt me to download a file. When I downloaded the file, it is actually the Json object array. Right there, I realized that the IE is actually calling the Json controller method as opposed to the standard non-Json controller method.

    Observations:
    1. I compared the standard non-Json controller method (list) to my old version, I've noticed the old method changed from @RequestMapping(method = RequestMethod.GET) to @RequestMapping(produces = "text/html").
    Obviously in this default case, Firefox knows to call the non-Json controller method whereas IE doesn't, it just goes to call the Json controller method where the @RequestMapping(headers="Accept=application/json").

    2. I then removed the produces = "text/html" from the @RequestMapping. Guess what, IE works fine this time by listing objects into a CRUD table, whereas Firefox didn't work, it displays the object array in Json format.

    Questions:
    1. Why is produces = "text/html" introduced to @RequestMapping in Roo 1.2.2? Is this anything do to with the newly introduced "web mvc json" command?

    2. It's clear to me that IE and FF handle the "produces="text/html"" differently. Does anyone know if this is a known issue?

    3. Our web app used to work on both browsers (IE and FF), however, after upgrade, it only works on one of them depends on how I configure the @RequestMapping.

    We love Roo, however, if it cannot support both browsers out of the box for standard operations like this, then it will become a major issue for us. I hope it is either a bug or something that I can easily enable/modify on my end to fix this issue.

    Your help is much appreciated!

    Thanks!
    Last edited by 3panda; Aug 2nd, 2012, 07:42 PM.

  • #2
    Trace the calls in the browser, watch the accept and content-type headers.

    Activate Debug-log:
    log4j.logger.org.springframework.web=DEBUG, stdout
    log4j.additivity.org.springframework.web=false

    See how spring maps the calls onto controller methods.

    @RequestMapping(produces = "text/html") does not mean that the browser knows something. It just influences which method is used to serve the request. In this case the client must accept text/html.

    Comment


    • #3
      Hi spgmx,

      Thank you for your quick reply.

      log4j was already enabled on our end. Please see the following logs for the same <a href > link request /users?page=1&size=25 on both Firefox and IE:

      Firefox: (From the trace below, you can see Spring routes standard <a href >link request /users?page=1&size=25 to com.demo.web.DemoAppController.list() (a non-Json controller method, desired behavior)

      1. org.springframework.security.web.FilterChainProxy$ VirtualFilterChain.doFilter(FilterChainProxy.java: 318) : /users?page=1&size=25 at position 1 of 11 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'

      2. org.springframework.security.web.util.AntPathReque stMatcher.matches(AntPathRequestMatcher.java:103) : Checking match of request : '/users'; against '/users/**'

      3. org.springframework.web.servlet.DispatcherServlet. doService(DispatcherServlet.java:799) : DispatcherServlet with name 'demoapp' processing GET request for [/demoapp/users]

      4. org.springframework.web.servlet.handler.AbstractHa ndlerMethodMapping.getHandlerInternal(AbstractHand lerMethodMapping.java:211) : Looking up handler method for path /users

      5. org.springframework.web.servlet.handler.AbstractHa ndlerMethodMapping.getHandlerInternal(AbstractHand lerMethodMapping.java:218) : Returning handler method [public java.lang.String com.demo.web.DemoAppController.list(java.lang.Inte ger,java.lang.Integer,org.springframework.ui.Model )]


      IE: (From the trace below, you can see the Spring routes the same standard <a href> link request /users?page=1&size=25 to com.demo.web.DemoAppController.listJson() (Json controller method, not desired behavior)

      1. org.springframework.security.web.FilterChainProxy$ VirtualFilterChain.doFilter(FilterChainProxy.java: 318) : /users?page=1&size=25 at position 1 of 11 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'

      2. org.springframework.security.web.util.AntPathReque stMatcher.matches(AntPathRequestMatcher.java:103) : Checking match of request : '/users'; against '/users/**'

      3. org.springframework.web.servlet.DispatcherServlet. doService(DispatcherServlet.java:799) : DispatcherServlet with name 'demoapp' processing GET request for [/demoapp/users]

      4. org.springframework.web.servlet.handler.AbstractHa ndlerMethodMapping.getHandlerInternal(AbstractHand lerMethodMapping.java:211) : Looking up handler method for path /users

      5. org.springframework.web.servlet.handler.AbstractHa ndlerMethodMapping.getHandlerInternal(AbstractHand lerMethodMapping.java:218) : Returning handler method [public org.springframework.http.ResponseEntity<java.lang. String> com.alu.bsx.web.DemoAppController.listJson()]


      So, somehow in the upgraded Roo 1.2.2, the routing function behaves differently than Roo 1.1.5. I’ve noticed the new Annotation @RooWebJson was introduced to Java Controller class, not sure if it has something to do with the routing logic behind.

      From the above trace, I think the magic lies in org.springframework.web.servlet.handler.AbstractHa ndlerMethodMapping.getHandlerInternal(), this is where Spring decides which method to serve the request.
      I’d appreciate if you could take a look at it and see if it had any logic changes from previous version. I will also look at it from my end as well. If we can both work on it, we can probably speed up the investigation as others may experience the same issue.

      Thank you!
      3Panda

      Comment


      • #4
        When the app starts up if lists all request mappings. You have to look there.

        e.g.:

        org.springframework.web.servlet.mvc.method.annotat ion.RequestMappingHandlerMapping - Mapped "{[/foo/bar],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public void foobar()..

        Comment


        • #5
          Hi spgmx,

          Please see below. Same URI request with different produces (one for text/html and the other for application/json format). Keep in mind that our <a href> request is simply asking for html response.

          1. Mapped "{[/users],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public java.lang.String com.demo.web.DemoAppUserController.list(java.lang. Integer,java.lang.Integer,org.springframework.ui.M odel)

          2. Mapped "{[/users],methods=[],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public org.springframework.http.ResponseEntity<java.lang. String> com.demo.web.DemoAppUserUserController.listJson()

          Any more thoughts?
          Thanks,
          3Panda

          Comment


          • #6
            Hi spgmx,

            I’ve captured the HTTP request headers for both Firefox and IE for you to review.

            I think I may know the issue. See the Accept part of the headers. Firefox's Accept has text/html, whereas IE doesn’t. Now, in Roo's standard generated non-Json controller method, it specifies produces=”text/html” in @RequestMapping. In Firefox case, Spring knows it wants to accept html, so it routes to non-Json method, good. However, in IE case, since it doesn’t has text/html in accept part of the header, Spring did its best guess and somehow route it to Json method instead. So, something got changed in the logic. I hope this helps.

            Thanks,
            3panda

            Firefox:
            Request Headers
            GET http://serverip/demoapp/users?page=1&size=25 HTTP/1.1
            Accept: text/html, application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8

            IE:
            Request Headers
            GET http://serverip/demoapp/users?page=1&size=25 HTTP/1.1
            Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*

            Comment


            • #7
              If you still regard this a bug perhaps you should enter it into the JIRA?

              Comment


              • #8
                You have 2 times the same url, once with application/json and ones with text/html. IE sends */* - "I understand everything". So what shall spring do? Send json, send html? "So what! He understands everything, so I send what I want." Spring will just use the first match and serve the request.

                Comment


                • #9
                  Thanks MiB and spgmx.

                  Couple of thoughts:
                  1. We will investigate a bit more before considering a JIRA;

                  2. FF is a great browser, however, the reality is that IE is still supported and used by a lot of Enterprise customers. So multi browser support is a key factor. IE browser engine’s accept header is historically different from FF Gecko’s (i.e. FF gives text/html the highest priority with relative quality parameters =1). Just speaking for myself, the routing should be explicitly as much as possible. If */* (give me whatever) is specified in IE, I’d hope Spring will serve text/html over Json. As most of the time, people are generally just requesting web pages.

                  Comment


                  • #10
                    Content negotiation gets tricky when the Accept-Headers are not explicit. */* means - I take everything, send what you want.
                    Therefore offen a url-suffix is used: .html for html and .json for json.

                    Comment


                    • #11
                      Some updates:

                      1) The problem only happened in IE 8. Our app worked in IE 9 as IE 9 now sends more specific Accept header based on which HTML element initiated the request, just like Firefox;

                      2) We’ve found a workaround for IE 8: For non-Json controller, I've pushed in the list function from Roo generated aj to java, I’ve changed @RequestMapping(produces = “text/html”) to @RequestMapping(produces = {“text/html”, “*/*”});

                      3) Based on our finding/experience, Spring mvc is all good. However, I am not sure if you consider this as a minor bug on Roo side. Or maybe an enhancement is needed in the routing function.

                      Once again, thanks for all your help!
                      3panda
                      Last edited by 3panda; Aug 8th, 2012, 04:05 PM.

                      Comment


                      • #12
                        Originally posted by 3panda View Post
                        Some updates:

                        1) The problem only happened in IE 8. Our app worked in IE 9 as IE 9 now sends more specific Accept header based on which HTML element initiated the request, just like Firefox;

                        2) We’ve found a workaround for IE 8: For non-Json controller, I've pushed in the list function from Roo generated aj to java, I’ve changed @RequestMapping(produces = “text/html”) to @RequestMapping(produces = {“text/html”, “*/*”});

                        3) Based on our finding/experience, Spring mvc is all good. However, I am not sure if you consider this as a minor bug on Roo side. Or maybe an enhancement is needed in the routing function.

                        Once again, thanks for all your help!
                        3panda
                        Thank you for this entire thread and all your helpful posts. I was searching for this exact problem on my side and this is the only place I could find an answer. Well done on your investigation and findings. I have also pushed the list method to my controller and modified it as per your suggestion to resolve my problem, although im a little annoyed that I have to produce my own list method in my controller. I like the fact that roo generates the methods for me so my java src files stay clean, but now whenever I want to use REST and a web view I will have to always override the default generated roo method to make sure the web view works with all browsers instead of silly IE8 asking me to download the json response.

                        Comment

                        Working...
                        X