Announcement Announcement Module
Collapse
No announcement yet.
Changing HTTP Status Code for Flex/Flash Client Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Changing HTTP Status Code for Flex/Flash Client

    I have a problem which seems to be the result of standards bodies and vendors not being in sync (this never happens does it?).

    The WS-I profile apparently mandates that the HTTP Status code be set to 500 any time a Fault is returned. However, due to some apparent limitations in the browser, Flex and Flash clients cannot process the body of an HTTP response for any HTTP status code other than 200. This causes a bit of a problem since my Flex client now reports an IOError for ANY SOAP Fault since it cannot read the Fault message. The solution I have found advocated by others is to filter the response and change the HTTP Status of 500 to 200.

    Therefore, I have two questions:

    1) What is the best way to intercept the response and change the status?

    Although I am uneasy about intentionally circumventing the specification, it seems I have no choice if I want this to work with Flex/Flash. However, if at all possible I would like to leave the status code alone for other clients (e.g. another Spring-WS Java client, etc.). Thus, my 2nd question ...

    2) What is the best way to make the determination of what type of client is accessing the web service?

    Any other suggestions are also appreciated. Thanks in advance.

    Bill

  • #2
    Changing HTTP Status Code for Flex/Flash Client

    It appears that there is an option in the WebServiceTemplate that overrides its default behavior of looking for a status of 500 to indicate a fault. However, I am so far unable to find any way to override the default behavior on the server.

    Since the status code needs to be set before sending the response, I think it is going to require changes or customization to the Spring-WS core classes. So far I have been able to find where setFault() is called, resulting in a status of 500 being set on the response, but these classes are not configured as Spring beans as nearly as I can find so I don't see an easy way to substitute a customized version of the class that sets the status to 200 for a Flex/Flash client without changing the core source and recompiling.

    Is there an easier way?

    Bill

    Comment


    • #3
      Possible Solution

      I found a proposed (partial) solution for my problem at the following link.

      http://stackoverflowexception.blogsp...n-in-flex.html

      The basic idea is to add a filter to the servlet (the article actually does this for XFire rather than Spring-WS) that retrieves, the HttpResponse, wraps it in a custom response class, and passes the wrapped response for processing by the web services implementation. The custom response class merely overrides the method used to set the HTTP status and substitutes 200 for 500 in all cases.

      This still doesn't fully satisfy me since it changes the behavior for all clients, but I'm one step closer. Now I just have to figure out a way to predictably identify a Flash/Flex client from other potential clients. I'm thinking it needs to be either a custom SOAP header or an HTTP header, but I haven't settled on an approach yet. I would still appreciate any comments or suggestions others might have on this problem. Thanks.

      Bill

      Comment


      • #4
        More problems

        I implemented the filter so I am now returning 200 any time a 500 would be returned by Spring-WS. I know it had the desired effect in Flex because my Flex client is now receiving the Fault body. But the Spring WS client now doesn't work. Because the HTTP status code is not 500, it does not process it as a Fault. According to the docs, WebServiceTemplate.setCheckConnectionForFault can be used to disable this behavior to accommodate non-conformant services, but I've tried setting to false it doesn't appear to have any effect.

        What do I need to do to allow the Spring client to work even if the web service is bastardized to return a successful HTTP status code?

        Or am I going to be forced to duplicate all of my services on two different URLs mapped to different endpoint URLs, one with the filter applied and one not?

        Bill

        Comment


        • #5
          Is this a bug?

          I am just getting familiar with the source so maybe I'm missing something, but I think this might be a bug. The checkConnectionForFault flag appears to be checked in hasFault(), but when the status code is 200, this method never gets called. The hasError() method is called which immediately checks the status code ... if it is 200, then no error. If no error, the rest of the hasError code is bypassed. Then the response message is requested ... well there isn't one because the body has only the Fault ... so response is null. If response is null then all the remaining code containing hasFault() is also bypassed. So if the status is 200, a fault will never be reported no matter what you do.

          Is this a bug? Or was the expectation that even though some services might not adhere to the spec and return 500, they would all at least return an error status rather than a success status?

          I am about to conclude that the only hope is to deploy two servlets, one with the filter and one without, and expose them on different URLs. Flex clients call one set of services and everyone else uses the others.

          Any suggestions? Man is this frustrating ... don't any of these vendors that participate in all these standards bodies ever talk to each other?


          Bill

          Comment


          • #6
            One more question

            Is there any problem with deploying two instances of MessageDispatcherServlet in the same web application? That is, do they share any application wide data or configuration that would cause a problem? In other words, can I just deploy two servlets or do I need two completely separate web applications? Please tell me it is the former ... please.

            Bill

            Comment


            • #7
              Problem Solved, but Still Interested in Comments

              I have solved the problem adequately for my needs for now, but I am still not entirely satisfied and would still be interested if others have comments.

              I created two instances of MessageDispatcherServlet in my web application, one with the filter that overrides the 500 status code with 200 for Flex and one that has no such filter. So far this does not cause any problems, but I'm keeping my fingers crossed.

              Both servlets share the same set of XML config files so they are mirror images except for two things ...

              1) each has a file with a PropertyPlaceholderConfigurer that is configured to use a properties file unique to that servlet and 2) each has its own copy of the aforementioned properties file which contains the endpoint URI's for the web services (which are different for the two servlets). The WSDL generator beans use property placeholders for the URI's so that the endpoint URI in the generated WSDL will be correct.

              So far this seems to work and requires minimal redundancy, but it is just a little disappointing that web services would turn out to be not interoperable as one might like. A kludge like this really should not be necessary.

              Sigh!

              Bill

              Comment


              • #8
                Originally posted by bill_bailey View Post
                I am just getting familiar with the source so maybe I'm missing something, but I think this might be a bug. The checkConnectionForFault flag appears to be checked in hasFault(), but when the status code is 200, this method never gets called. The hasError() method is called which immediately checks the status code ... if it is 200, then no error. If no error, the rest of the hasError code is bypassed. Then the response message is requested ... well there isn't one because the body has only the Fault ... so response is null. If response is null then all the remaining code containing hasFault() is also bypassed. So if the status is 200, a fault will never be reported no matter what you do.
                The algorithm in the template is meant to deal with both Plain Old Xml Web Services, and SOAP services. It also takes into account that some message factories use streaming, i.e. they lazily load the response message. Therefore, the template tries to use status codes as much as possible. If we would read the entire message just to find out whether it has a fault or not, it will always read the message in memory, i.e. no more streaming.

                One thing to note is that when a response has a SOAP fault, it is not null. It is just a message which contains a fault in its body. For your particular problem, this means that you could set the "checkConnectionForFault" property to false, which means that the status code is ignored, and the message is read (i.e. SoapMessage.hasFault() is returned).

                Originally posted by bill_bailey View Post
                Any suggestions? Man is this frustrating ... don't any of these vendors that participate in all these standards bodies ever talk to each other?
                Welcome to the level of hell that is interoperability. I've been a resident here for quite some time.

                Comment


                • #9
                  Thanks

                  Thanks, Arjen.

                  It is good to know that I could get to the fault information if I really need to, but I guess I'll leave well enough alone for now. Even though there are some negative aspects to my current solution (e.g. each servlet creates a separate web application context so I have two database connection pools, two ticket caches, etc.), it meets my needs for the moment. Initially, we will probably only have a need for the flex web services anyway, but I was trying to leave the door open to reuse in the future.

                  It is also good to know that I am not alone in 'interoperability hell'.

                  Bill

                  Comment


                  • #10
                    @Bill

                    I've found a better solution on blog[dot]widget-labs[dot]com
                    Write a servlet filter that will change the status code.
                    Code:
                    	<filter>
                    		<filter-name>SpringWsResponseFilter</filter-name>
                    		<filter-class>SpringWsResponseFilter</filter-class>
                    	</filter>
                    	<filter-mapping>
                    		<filter-name>SpringWsResponseFilter</filter-name>
                    		<servlet-name>spring-ws</servlet-name>
                    	</filter-mapping>
                    Code:
                    public class SpringWsResponseFilter implements Filter {
                    
                      public void destroy() {
                    
                      }
                    
                      public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain)
                          throws IOException, ServletException {
                        final HttpServletResponse httpResponse = (HttpServletResponse) response;
                        final ExceptionHttpServletResponseWrapper wrapper = new ExceptionHttpServletResponseWrapper(httpResponse);
                        filterChain.doFilter(request, wrapper);
                      }
                    
                      public void init(final FilterConfig arg0) throws ServletException {
                      }
                    
                      /**
                       * Changes HTTP status code from 500 to 200 for air application to understand
                       */
                      private static class ExceptionHttpServletResponseWrapper extends HttpServletResponseWrapper {
                        public ExceptionHttpServletResponseWrapper(final HttpServletResponse response) {
                          super(response);
                        }
                    
                        @Override
                        public void setStatus(final int statusCode) {
                          if (statusCode == 500) {
                            super.setStatus(200);
                          }
                        }
                      }
                    }

                    Comment


                    • #11
                      I was searching the solution for the similar problem. Thanks for all the information and vital source code you have given here. It really helped me to solve my problem.
                      ___________________
                      Flash Website Development

                      Comment


                      • #12
                        Since the status code needs to be set before sending the response, I think it is going to require changes or customization to the Spring-WS core classes. So far I have been able to find where setFault() is called, resulting in a status of 500 being set on the response, but these classes are not configured as Spring beans as nearly as I can find so I don't see an easy way to substitute a customized version of the class that sets the status to 200 for a Flex/Flash client without changing the core source and recompiling.

                        Is there an easier way?

                        Comment


                        • #13
                          Hi Guys,
                          I know, it is a old post. But I am facing the same issue. May be as mentioned above, I am getting correct error message in Flex. But when I am testing my API in external api tester (like Poster, Curl), it is throwing Status 200 with error msg. Whereas it shouldn’t happen. It should throw error code as 500. Is there any way to handle this?

                          Comment

                          Working...
                          X