Руководство по весенним перенаправлениям

Руководство по весенним перенаправлениям

1. обзор

В этой статье мы сосредоточимся наimplementing a Redirect in Spring и обсудим аргументы, лежащие в основе каждой стратегии.

Дальнейшее чтение:

Перенаправление на разные страницы после входа в Spring Security

Пример того, как перенаправить на разные страницы после входа в Spring Security.

Read more

Spring Security - Перенаправление на предыдущий URL после входа в систему

Краткий пример перенаправления после входа в Spring Security

Read more

Управляйте сеансом с помощью Spring Security

Настройте сеансы с помощью Spring Security - настройте параллельные сеансы, включите защиту фиксации сеансов и запретите URL-адресам содержать информацию о сеансах.

Read more

2. Зачем нужен редирект?

Давайте сначала рассмотримthe reasons why you may need to do a redirect в приложении Spring.

Есть много возможных примеров и причин, конечно. Одним из простых может быть отправка данных формы POST, обход проблемы с двойной передачей или просто делегирование потока выполнения другому методу контроллера.

Небольшое примечание: типичный шаблон «Опубликовать / Перенаправить / Получить» неадекватно решает проблемы двойной отправки - такие проблемы, как обновление страницы до завершения первоначальной отправки, все равно могут привести к двойной отправке.

3. Перенаправление сRedirectView

Начнем с этого простого подхода - иgo 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");
    }
}

За кулисамиRedirectView вызоветHttpServletResponse.sendRedirect(), который выполнит фактическое перенаправление.

Обратите внимание, какwe’re injecting the redirect attributes into the method - структура сделает здесь тяжелую работу и позволит нам взаимодействовать с этими атрибутами.

Мы добавляем атрибут моделиattribute –, который будет отображаться как параметр HTTP-запроса. Модель должна содержать только объекты - обычно строки или объекты, которые можно преобразовать в строки.

Давайте теперь протестируем наше перенаправление - с помощью простой командыcurl:

curl -i http://localhost:8080/spring-rest/redirectWithRedirectView

Результатом будет:

HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location:
  http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectView

4. Перенаправление с префиксомredirect:

Предыдущий подход - использованиеRedirectView – неоптимален по нескольким причинам.

Во-первых, теперь мы подключены к Spring API, потому что мы используемRedirectView непосредственно в нашем коде.

Во-вторых, теперь нам нужно знать с самого начала, при реализации этой операции контроллера, что результатом всегда будет перенаправление, что может не всегда иметь место.

Лучшим вариантом является использование префиксаredirect: - имя представления перенаправления вводится в контроллер, как и любое другое имя логического представления. The controller is not even aware that redirection is happening.

Вот как это выглядит:

@Controller
@RequestMapping("/")
public class RedirectController {

    @GetMapping("/redirectWithRedirectPrefix")
    public ModelAndView redirectWithUsingRedirectPrefix(ModelMap model) {
        model.addAttribute("attribute", "redirectWithRedirectPrefix");
        return new ModelAndView("redirect:/redirectedUrl", model);
    }
}

Когда имя представления возвращается с префиксомredirect:,UrlBasedViewResolver (и все его подклассы) распознают это как особое указание на необходимость перенаправления. Остальная часть имени представления будет использоваться в качестве URL перенаправления.

Быстрое, но важное замечание: когда мы используем здесь это логическое имя представления -redirect:/redirectedUrl - мы выполняем перенаправлениеrelative to the current Servlet context.

Мы можем использовать такое имя, какa redirect: http://localhost:8080/spring-redirect-and-forward/redirectedUrl, если нам нужно перенаправить на абсолютный URL.

Итак, теперь, когда мы выполняем командуcurl:

curl -i http://localhost:8080/spring-rest/redirectWithRedirectPrefix

Нас сразу же перенаправят:

HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location:
  http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectPrefix

5. Вперед с префиксомforward:

Давайте теперь посмотрим, как сделать что-то немного другое - вперед.

Перед кодом пройдемся поa quick, high-level overview of the semantics of forward vs. redirect:

  • redirect ответит 302 и новым URL-адресом в заголовкеLocation; браузер / клиент затем сделает еще один запрос на новый URL

  • forward происходит полностью на стороне сервера; контейнер сервлета пересылает тот же запрос на целевой URL; URL не изменится в браузере

Теперь посмотрим на код:

@Controller
@RequestMapping("/")
public class RedirectController {

    @GetMapping("/forwardWithForwardPrefix")
    public ModelAndView redirectWithUsingForwardPrefix(ModelMap model) {
        model.addAttribute("attribute", "forwardWithForwardPrefix");
        return new ModelAndView("forward:/redirectedUrl", model);
    }
}

Как иredirect:, префиксforward: будет разрешенUrlBasedViewResolver и его подклассами. Внутренне это создастInternalResourceView, который выполняетRequestDispatcher.forward() для нового представления.

Когда мы выполняем команду сcurl:

curl -I http://localhost:8080/spring-rest/forwardWithForwardPrefix

Мы получим HTTP 405 (метод не разрешен):

HTTP/1.1 405 Method Not Allowed
Server: Apache-Coyote/1.1
Allow: GET
Content-Type: text/html;charset=utf-8

Чтобы подвести итог, по сравнению с двумя запросами, которые у нас были в случае решения по перенаправлению, в этом случае у нас есть только один запрос от браузера / клиента на сторону сервера. Атрибут, который был ранее добавлен перенаправлением, также, конечно, отсутствует.

6. Атрибуты сRedirectAttributes

Далее - давайте внимательнее рассмотримpassing attributes in a redirect - полное использование фреймворка сRedirectAttribures:

@GetMapping("/redirectWithRedirectAttributes")
public RedirectView redirectWithRedirectAttributes(RedirectAttributes attributes) {

    attributes.addFlashAttribute("flashAttribute", "redirectWithRedirectAttributes");
    attributes.addAttribute("attribute", "redirectWithRedirectAttributes");
    return new RedirectView("redirectedUrl");
}

Как мы уже видели, мы можем напрямую добавить объект атрибутов в метод, что делает этот механизм очень простым в использовании.

Также обратите внимание, чтоwe are adding a flash attribute as well - это атрибут, который не попадет в URL. Чего мы можем достичь с помощью этого типа атрибута, так это то, что позже мы сможем получить доступ к атрибуту flash, используя@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);
 }

Итак, подведем итоги - если мы протестируем функциональность с помощьюcurl:

curl -i http://localhost:8080/spring-rest/redirectWithRedirectAttributes

Мы будем перенаправлены на новое место:

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

Таким образом, использованиеRedirectAttribures вместоModelMap дает нам возможность делиться толькоsome attributes between the two methods, которые участвуют в операции перенаправления.

7. Альтернативная конфигурация без префикса

Давайте теперь рассмотрим альтернативную конфигурацию - перенаправление без использования префикса.

Для этого нам нужно использоватьorg.springframework.web.servlet.view.XmlViewResolver:


    
        /WEB-INF/spring-views.xml
    
    

Вместоorg.springframework.web.servlet.view.InternalResourceViewResolver мы использовали в предыдущей конфигурации:


Нам также необходимо определить bean-компонентRedirectView в конфигурации:


    

Теперь мы можемtrigger 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);
    }
}

И чтобы проверить это, мы снова воспользуемся командойcurl:

curl -i http://localhost:8080/spring-rest/redirectWithRedirectView

Результатом будет:

HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location:
  http://localhost:8080/spring-rest/redirectedUrl?attribute=redirectWithRedirectView

8. Перенаправление HTTP-запроса POST

Для случаев использования, таких как банковские платежи, нам может потребоваться перенаправить HTTP-запрос POST. В зависимости от возвращенного кода состояния HTTP, запрос POST может быть перенаправлен на HTTP GET или POST.

Согласно протоколу HTTP 1.1reference, коды состояния 301 (перемещено постоянно) и 302 (найдено) позволяют изменять метод запроса с POST на GET. В спецификации также определены соответствующие коды статуса 307 (временное перенаправление) и 308 (постоянное перенаправление), которые не позволяют изменять метод запроса с POST на GET.

Теперь давайте посмотрим на код для перенаправления почтового запроса на другой почтовый запрос:

@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

Мы перенаправлены в пункт назначения:

> 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. Заключение

В этой статье показано, какthree different approaches to implementing a redirect in Spring обрабатывать / передавать атрибуты при выполнении этих перенаправлений, а также как обрабатывать перенаправления запросов HTTP POST.