2

Every request in my java application produces 2 other requests with a HTTP 302 error.

For example, if a request is made to view a webpage called board.html, this request is made from home.html. I get 3 requests produced in the following order:

POST home.html - 302 Moved Temporarily
GET board.html - 302 Moved Temporarily
GET board.html - 200 OK

I expect to get just the final request only and cant find out why the other 2 are occurring.

This pattern occurs for all requests causing my filters to fire 3 times.

The project uses spring webflow.

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
Rob
  • 31
  • 1
  • 4
  • 2
    Spring WebFlow uses the POST-REDIRECT-GET idiom by default. This means that every POST is followed by a 302 redirect. This would explain one of your two 302 responses. I don't know why you'd be seeing a second (unless something else in your app is triggering it). You can change the POST-REDIRECT-GET behaviour using `alwaysRedirectOnPause` in your WebFlow config. Check out [http://www.ervacon.com/products/swf/tips/tip4.html] for some more info on this behaviour. – Will Keeling Jun 11 '13 at 14:25
  • 2
    What Will said is correct. I'll point out that 302 is not an error, and the way Spring Web Flow works, redirects are normal and serve a useful purpose. So I wouldn't go disable them without knowing exactly what you're losing/gaining. One is normal with Web Flow. I'd guess the application itself is causing the second one. – dbreaux Jun 11 '13 at 23:13
  • Thank you both for helping me understand this. It is indeed caused by webflows alwaysRedirectOnPause setting and i managed to prevent the 302 on the called resource by setting it to FALSE. However as you point out dbreaux this behaviour is there for a good reason in that it prevents double submits so it is something I am going to have to work with rather than disabling. – Rob Jun 12 '13 at 09:29

1 Answers1

0

After lot of reading was finally able to change the default behaviour ( default behaviour was - Get request , post (302/303 - redirect as per location appended for each request ) , finally a get call.

So for one request we will send a Get Request then Service will return 302/303 with location attribute ( ie redirected with query param ) and as a response HTML with QueryString usually e1s1 is loaded. Sample proj is in this link and following is the change that is been implemented to avoid this default behaviour as following

To avoid 303/302 which has unpredictable behaviour i have stoped redirection with following addition to Config Class

@Configuration
public class WebFlowWithMvcConfig extends AbstractFlowConfiguration  {
    //implements WebMvcConfigurer
    @Autowired
    private LocalValidatorFactoryBean localValidatorFacotryBean;
    /*
    @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new LogInterceptor());
        }
     */
    
    @Bean
    public FlowDefinitionRegistry flowRegistry() {
        return getFlowDefinitionRegistryBuilder() //
                .setBasePath("classpath:flows") //
                .addFlowLocationPattern("/**/*-flow.xml") //
                .setFlowBuilderServices(this.flowBuilderServices()) //
                .build();
    }

    @Bean
    public FlowExecutor flowExecutor() {
        return getFlowExecutorBuilder(this.flowRegistry()) 
                .setAlwaysRedirectOnPause(false)
                .setRedirectInSameState(false) 
                .build();
    }

    @Bean
    public FlowBuilderServices flowBuilderServices() {
        return getFlowBuilderServicesBuilder() //
                .setViewFactoryCreator(this.mvcViewFactoryCreator()) // Important!
                .setValidator(this.localValidatorFacotryBean)
                .build();
    }
    // ----------------------------------------------------------

    @Bean
    public FlowHandlerMapping flowHandlerMapping() {
        FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
        handlerMapping.setOrder(-1);
        handlerMapping.setFlowRegistry(this.flowRegistry());
        //handlerMapping.setInterceptors(new LogInterceptor());
        return handlerMapping;
    }

    @Bean
    public FlowHandlerAdapter flowHandlerAdapter() {
        FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
        handlerAdapter.setFlowExecutor(this.flowExecutor());
        handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
        //handlerAdapter.setStatusCode(HttpStatus.SEE_OTHER);
        //handlerAdapter.setStatusCode(HttpStatus.TEMPORARY_REDIRECT);
        return handlerAdapter;
    }

    @Bean
    public ViewFactoryCreator mvcViewFactoryCreator() {
        MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
        factoryCreator.setViewResolvers(Collections.singletonList(this.thymeleafViewResolver()));
        factoryCreator.setUseSpringBeanBinding(true);
        return factoryCreator;
    }

    @Bean
    @Description("Thymeleaf AJAX view resolver for Spring WebFlow")
    public AjaxThymeleafViewResolver thymeleafViewResolver() {
        AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
        viewResolver.setViewClass(FlowAjaxThymeleafView.class);
        viewResolver.setTemplateEngine(this.templateEngine());
        viewResolver.setCharacterEncoding("UTF-8");
        return viewResolver;
    }

    @Bean
    @Description("Thymeleaf template resolver serving HTML 5")
    public ClassLoaderTemplateResolver templateResolver() {
        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setPrefix("templates/");
        templateResolver.setCacheable(false);
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode("HTML5");
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }

    @Bean
    @Description("Thymeleaf template engine with Spring integration")
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(this.templateResolver());
        return templateEngine;
    }
}

So we have made following as false

            .setAlwaysRedirectOnPause(false)
            .setRedirectInSameState(false) 

Which will avoid location redirect now the similar change has to be implemented in the template html's too. So the change was to add an action url to html template wherever form is present as following

<form ..  th:action="${flowExecutionUrl}">

Which successfully does form submission and responds with 200 Ok http status and html page. Hence no more (GET - 200 to 302 redirect to 200) instead direct single request call with Get 200/Post 200 and response is binded to Html page.

In this way just the final request only with response is present. I hope this would be helpful for others.

Parameshwar
  • 856
  • 8
  • 16