Announcement Announcement Module
Collapse
No announcement yet.
Forcing 304 instead of 200 HTTP response? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Forcing 304 instead of 200 HTTP response?

    I'm storing images in the DB, some of which are used to allow companies to brand an application.

    I've got a Handler configured to detect URLs that are for retrieving images.

    Currently, the image is retrieved every time.

    I want to give the browser a 304 response so (I think?) it will use the image from it's own cache, thereby improving overall response time and decreasing the amount of bandwidth used.

    Does anyone know to do this?

    I've tried doing the following

    response.addDateHeader("Last-Modified", lastModified);
    response.addDateHeader("Expires" , -1);

    after which I write the image bytestream back to the browser.

  • #2
    I've also done:

    response.setStatus(HttpServletResponse.SC_NOT_MODI FIED); // 304

    but I guess I'm unsure about the right way to detect if a 304 should be sent back.

    i.e. how do you know if the browser has a copy in the first place so that it's safe to do a 304 instead of a 200, i.e. send image back?

    Currently it seems i'm doing a 304, but still sending the image back over the wire which is still using up bandwidth.

    Comment


    • #3
      If you use a servlet to serve the images, ie. have an <img src="/servlet/imageServlet"> in the HTML to retrieve it, then the browser should use it's own cache.

      If you need to prepare the data beforehand, you can store data in the session and remove it as soon as the servlet has processed it.

      Also, why are you storing the images in the actual database? It's lot faster to store the images on the file system and store the file location in the database. If you have a lot of images, you can also split them across multiple hard-drives by using a simple hashing algorithm to reduce file I/O.

      Bob

      Comment


      • #4
        Also, why are you storing the images in the actual database
        Because it's a leased web application, that lots of different companies use, and they can all upload their own logos, etc.

        Can we please just have answers that try to solve the problem assuming the images are stored in the DB?

        Comment


        • #5
          Originally posted by gmatthews
          Because it's a leased web application, that lots of different companies use, and they can all upload their own logos, etc.

          Can we please just have answers that try to solve the problem assuming the images are stored in the DB?
          1) I did answer the question, you can use a servlet to serve the images and the browser will use it's cache

          2) Allowing customers to upload their own images does not mean that those images have to be stored in a DB

          Bob

          Comment


          • #6
            Originally posted by gmatthews
            after which I write the image bytestream back to the browser.
            you've just answered your own question about why the image still gets sent over the wire right there

            Nothing in your posts indicates which aspects of Spring you're using to handle the image requests - it's all generic servlet stuff. Are you using standard MVC Controllers?

            Regards,

            Comment


            • #7
              The workflow you needs is as follows:

              - browser requests image
              - get the image (or at least it's last modified date)
              - set the last modified date
              - server checks to see if there is a lastModifiedDate
              - if there is
              - check the last modified date of the image
              - if the image hasn't been modified
              - return a 304
              - end if
              - end if
              - return the image

              Remember, the browser will know about it's own cache it will simply ask you if the object has been changed via the lastModifiedHeader.

              I always set the LMD (even on 304) because IE and firefox seem to do funny things if not.

              To be hones, judging by your questions; I would read up on 304 and caches and the various headers first
              Originally posted by gmatthews
              I've also done:

              response.setStatus(HttpServletResponse.SC_NOT_MODI FIED); // 304

              but I guess I'm unsure about the right way to detect if a 304 should be sent back.

              i.e. how do you know if the browser has a copy in the first place so that it's safe to do a 304 instead of a 200, i.e. send image back?

              Currently it seems i'm doing a 304, but still sending the image back over the wire which is still using up bandwidth.

              Comment


              • #8
                Yeah, I think I need a bit more in depth understanding on this first.

                I've been playing around with:

                request.getHeader("If-Modified-Since")

                which I think is when the browser got it's latest copy of the image, but am still experimenting.

                I'll post any successful results I get.

                Comment


                • #9
                  Originally posted by gmatthews
                  request.getHeader("If-Modified-Since")
                  That's what you want! Just check for that, and if it exists and your image's updated date is newer, then send the new image. Otherwise, don't send anything and return a 304. Then, just return a null ModelAndView.

                  Comment


                  • #10
                    Checking for If-Modified-Since and sending back 304 or 200 works fine. The only thing is when parsing the date, it's in GMT so you need to set a TimeZone on your DateFormat instance to parse the request time back into local time.

                    I also noticed that Spring provides a org.springframework.web.servlet.mvc.LastModified interface that is supposed to be implemented by your controller.

                    DispatcherServlet and SimpleControllerHandlerAdapter co-ordinate to eventually call LastModifier.getLastModified

                    It might be interesting to see if support for sending back a 304 with a null ModelAndView (to indicate that the controller has already handled the request) could be put into Spring.

                    Comment


                    • #11
                      Originally posted by gmatthews
                      Checking for If-Modified-Since and sending back 304 or 200 works fine. The only thing is when parsing the date, it's in GMT so you need to set a TimeZone on your DateFormat instance to parse the request time back into local time.
                      You can use request.getDateHeader() / response.setDateHeader() to avoid having to faff with TimeZones. Confusingly they take a long, not a Date, but the conversion is easy (theDate.getTime() / new Date(longValue)

                      A couple of other things to watch out for:
                      - Firefox will only send conditional GET requests (i.e. include an if-modified-since) if you've previously set a last-modified date on the response;
                      - If you send a content-length header make sure it's zero for a 304 response else Safari will hang for about 30 seconds waiting for you to finish the response.

                      The LiveHttpHeaders firefox extension is invaluable for debugging / understanding what's going on here, as is Ethereal. Oh, and the spec (http://www.w3.org/Protocols/rfc2616/rfc2616.html )is surprisingly accessible.

                      Comment


                      • #12
                        Thanks very much for the info.

                        I am setting last-modified every time, but only out of luck I guess. I didn't know about the firefox issue.

                        I think I'll use the getDateHeader/setDateHeader + set the content length as you suggest.

                        Thanks also for the spec reference.

                        I wonder if this might be useful for those people doing AJAX or even Lazslo (sp?), and being able to cache generated content.

                        I vaguely remember working on some project in about 1997 where we were using XMLHttpRequest (pretty much AJAX) for an IE only app, and we had loads of big generated .js files that would have been good to cache.

                        Comment


                        • #13
                          Originally posted by gmatthews View Post
                          Checking for If-Modified-Since and sending back 304 or 200 works fine. The only thing is when parsing the date, it's in GMT so you need to set a TimeZone on your DateFormat instance to parse the request time back into local time.

                          I also noticed that Spring provides a org.springframework.web.servlet.mvc.LastModified interface that is supposed to be implemented by your controller.

                          DispatcherServlet and SimpleControllerHandlerAdapter co-ordinate to eventually call LastModifier.getLastModified

                          It might be interesting to see if support for sending back a 304 with a null ModelAndView (to indicate that the controller has already handled the request) could be put into Spring.
                          buy fans

                          Comment

                          Working...
                          X