Um guia para redirecionamentos de primavera
1. Visão geral
Este artigo se concentrará emimplementing a Redirect in Springe discutirá o raciocínio por trás de cada estratégia.
Leitura adicional:
Redirecionar para páginas diferentes após o login com o Spring Security
Exemplo de como redirecionar para páginas diferentes após o login com o Spring Security.
Spring Security - Redirecionar para o URL anterior após o login
Um pequeno exemplo de redirecionamento após o login no Spring Security
Controlar a sessão com Spring Security
Configurar sessões com Spring Security - configure sessões simultâneas, ative a proteção de fixação de sessão e evite que URLs contenham informações da sessão.
2. Por que fazer um redirecionamento?
Vamos primeiro considerarthe reasons why you may need to do a redirect em um aplicativo Spring.
Existem muitos exemplos e razões possíveis, é claro. Um simples pode ser o POST de dados de formulário, contornar o problema de envio duplo ou apenas delegar o fluxo de execução para outro método do controlador.
Uma observação rápida aqui é que o padrão Post / Redirect / Get típico não aborda adequadamente os problemas de envio duplo - problemas como atualizar a página antes que o envio inicial seja concluído podem ainda resultar em um envio duplo.
3. Redirecione com oRedirectView
Vamos começar com esta abordagem simples - ego straight to an example:
@Controller
@RequestMapping("/")
public class RedirectController {
@GetMapping("/redirectWithRedirectView")
public RedirectView redirectWithUsingRedirectView(
RedirectAttributes attributes) {
attributes.addFlashAttribute("flashAttribute", "redirectWithRedirectView");
attributes.addAttribute("attribute", "redirectWithRedirectView");
return new RedirectView("redirectedUrl");
}
}
Nos bastidores,RedirectView acionará umHttpServletResponse.sendRedirect() - que executará o redirecionamento real.
Observe aqui comowe’re injecting the redirect attributes into the method - o framework fará o trabalho pesado aqui e nos permitirá interagir com esses atributos.
Estamos adicionando o atributo de modeloattribute – que será exposto como parâmetro de consulta HTTP. O modelo deve conter apenas objetos - geralmente Strings ou objetos que podem ser convertidos em Strings.
Vamos agora testar nosso redirecionamento - com a ajuda de um comandocurl simples:
curl -i http://localhost:8080/spring-rest/redirectWithRedirectView
O resultado será:
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location:
http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectView
4. Redirecionar com o prefixoredirect:
A abordagem anterior - usarRedirectView – não é ideal por alguns motivos.
Primeiro, agora estamos acoplados à API Spring porque estamos usandoRedirectView diretamente em nosso código.
Segundo - agora precisamos saber desde o início, ao implementar a operação do controlador - que o resultado sempre será um redirecionamento - o que nem sempre pode ser o caso.
Uma opção melhor é usar o prefixoredirect: - o nome da visualização de redirecionamento é injetado no controlador como qualquer outro nome de visualização lógico. The controller is not even aware that redirection is happening.
Isso é o que parece:
@Controller
@RequestMapping("/")
public class RedirectController {
@GetMapping("/redirectWithRedirectPrefix")
public ModelAndView redirectWithUsingRedirectPrefix(ModelMap model) {
model.addAttribute("attribute", "redirectWithRedirectPrefix");
return new ModelAndView("redirect:/redirectedUrl", model);
}
}
Quando um nome de visualização é retornado com o prefixoredirect:–, oUrlBasedViewResolver (e todas as suas subclasses) reconhecerão isso como uma indicação especial de que um redirecionamento precisa acontecer. O restante do nome da visualização será usado como o URL de redirecionamento.
Uma nota rápida, mas importante, é que - quando usamos esse nome de visualização lógico aqui -redirect:/redirectedUrl - estamos fazendo um redirecionamentorelative to the current Servlet context.
Podemos usar um nome comoa redirect: http://localhost:8080/spring-redirect-and-forward/redirectedUrl se precisarmos redirecionar para uma URL absoluta.
Então, agora, quando executarmos o comandocurl:
curl -i http://localhost:8080/spring-rest/redirectWithRedirectPrefix
Seremos redirecionados imediatamente:
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location:
http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectPrefix
5. Avançar com o prefixoforward:
Vamos agora ver como fazer algo um pouco diferente - um avanço.
Antes do código, vamos passar dea quick, high-level overview of the semantics of forward vs. redirect:
-
redirect responderá com um 302 e a nova URL no cabeçalhoLocation; o navegador / cliente fará outra solicitação para o novo URL
-
forward acontece inteiramente no lado do servidor; o contêiner Servlet encaminha a mesma solicitação para a URL de destino; o URL não muda no navegador
Agora vamos dar uma olhada no código:
@Controller
@RequestMapping("/")
public class RedirectController {
@GetMapping("/forwardWithForwardPrefix")
public ModelAndView redirectWithUsingForwardPrefix(ModelMap model) {
model.addAttribute("attribute", "forwardWithForwardPrefix");
return new ModelAndView("forward:/redirectedUrl", model);
}
}
Da mesma forma queredirect:, o prefixoforward: será resolvido porUrlBasedViewResolvere suas subclasses. Internamente, isso criará umInternalResourceView que faz umRequestDispatcher.forward() para a nova visualização.
Quando executamos o comando comcurl:
curl -I http://localhost:8080/spring-rest/forwardWithForwardPrefix
Obteremos o HTTP 405 (método não permitido):
HTTP/1.1 405 Method Not Allowed
Server: Apache-Coyote/1.1
Allow: GET
Content-Type: text/html;charset=utf-8
Para finalizar, em comparação com as duas solicitações que tivemos no caso da solução de redirecionamento, neste caso, temos apenas uma solicitação saindo do navegador / cliente para o lado do servidor. O atributo que foi adicionado anteriormente pelo redirecionamento também está ausente.
6. Atributos comRedirectAttributes
A seguir - vamos olhar mais de perto empassing attributes in a redirect - fazendo uso total da estrutura comRedirectAttribures:
@GetMapping("/redirectWithRedirectAttributes")
public RedirectView redirectWithRedirectAttributes(RedirectAttributes attributes) {
attributes.addFlashAttribute("flashAttribute", "redirectWithRedirectAttributes");
attributes.addAttribute("attribute", "redirectWithRedirectAttributes");
return new RedirectView("redirectedUrl");
}
Como vimos anteriormente, podemos injetar diretamente o objeto de atributos no método - o que torna esse mecanismo muito fácil de usar.
Observe também quewe are adding a flash attribute as well - este é um atributo que não será incluído no URL. O que podemos alcançar com esse tipo de atributo é - podemos acessar posteriormente o atributo flash usando@ModelAttribute(“flashAttribute”)only in the method that is the final target of the redirect:
@GetMapping("/redirectedUrl")
public ModelAndView redirection(
ModelMap model,
@ModelAttribute("flashAttribute") Object flashAttribute) {
model.addAttribute("redirectionAttribute", flashAttribute);
return new ModelAndView("redirection", model);
}
Então, para finalizar - se testarmos a funcionalidade comcurl:
curl -i http://localhost:8080/spring-rest/redirectWithRedirectAttributes
Seremos redirecionados para o novo local:
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=4B70D8FADA2FD6C22E73312C2B57E381; Path=/spring-rest/; HttpOnly
Location: http://localhost:8080/spring-rest/redirectedUrl;
jsessionid=4B70D8FADA2FD6C22E73312C2B57E381?attribute=redirectWithRedirectAttributes
Dessa forma, usarRedirectAttribures em vez deModelMap nos dá a capacidade de compartilhar apenassome attributes between the two methods que estão envolvidos na operação de redirecionamento.
7. Uma configuração alternativa sem o prefixo
Vamos agora explorar uma configuração alternativa - um redirecionamento sem usar o prefixo.
Para conseguir isso, precisamos usar umorg.springframework.web.servlet.view.XmlViewResolver:
/WEB-INF/spring-views.xml
Em vez deorg.springframework.web.servlet.view.InternalResourceViewResolver, usamos na configuração anterior:
Também precisamos definir um beanRedirectView na configuração:
Agora podemostrigger the redirect by referencing this new bean by id:
@Controller
@RequestMapping("/")
public class RedirectController {
@GetMapping("/redirectWithXMLConfig")
public ModelAndView redirectWithUsingXMLConfig(ModelMap model) {
model.addAttribute("attribute", "redirectWithXMLConfig");
return new ModelAndView("RedirectedUrl", model);
}
}
E para testá-lo, usaremos novamente o comandocurl:
curl -i http://localhost:8080/spring-rest/redirectWithRedirectView
O resultado será:
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location:
http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectView
8. Redirecionando uma solicitação HTTP POST
Para casos de uso como pagamentos bancários, talvez seja necessário redirecionar uma solicitação HTTP POST. Dependendo do código de status HTTP retornado, a solicitação POST pode ser redirecionada para um HTTP GET ou POST.
De acordo com o protocolo HTTP 1.1reference, os códigos de status 301 (Movido Permanentemente) e 302 (Encontrado) permitem que o método de solicitação seja alterado de POST para GET. A especificação também define os códigos de status 307 (Redirecionamento temporário) e 308 (Redirecionamento permanente) correspondentes que não permitem que o método de solicitação seja alterado de POST para GET.
Agora vamos ver o código para redirecionar uma solicitação de postagem para outra solicitação de postagem:
@PostMapping("/redirectPostToPost")
public ModelAndView redirectPostToPost(HttpServletRequest request) {
request.setAttribute(
View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
return new ModelAndView("redirect:/redirectedPostToPost");
}
@PostMapping("/redirectedPostToPost")
public ModelAndView redirectedPostToPost() {
return new ModelAndView("redirection");
}
Now, let’s test the redirect of POST using the curl command:
curl -L --verbose -X POST http://localhost:8080/spring-rest/redirectPostToPost
Estamos sendo redirecionados para o local de destino:
> POST /redirectedPostToPost HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.49.0
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 08 Aug 2017 07:33:00 GMT
{"id":1,"content":"redirect completed"}
9. Conclusão
Este artigo ilustrouthree different approaches to implementing a redirect in Spring, como lidar / passar atributos ao fazer esses redirecionamentos e também como lidar com redirecionamentos de solicitações HTTP POST.