Explain the "redirect:" and "forward:" prefixes on a view name. How do they differ, and how do you carry data across a redirect without exposing it as query params?
answer
- redirect = 302, new request, URL changes
- forward = same request, server-side, URL same
- PRG avoids duplicate POST
- addFlashAttribute survives one redirect
- addAttribute -> query param
basics
~10 s"redirect:/x" sends a 302 telling the browser to request /x again (new request). "forward:/x" hands off server-side to another handler in the same request. To pass data over a redirect safely, use RedirectAttributes.addFlashAttribute.
solid answer
~40 sBoth are special prefixes Spring recognizes on the returned view name instead of resolving a template. "redirect:/orders/42" produces an HTTP 302 (or 303) redirect: the browser issues a brand-new request to that URL, so it's ideal after POST (Post/Redirect/Get) to avoid duplicate form submits. "forward:/internal" is a server-side RequestDispatcher forward — same request/response, no round trip, URL unchanged. Because a redirect starts a new request, request-scoped model data is lost; primitive model attributes get appended as query-string params (RedirectView). To pass data invisibly, use RedirectAttributes.addFlashAttribute(...), which stores values in flash storage (session-backed) that survives exactly one redirect and is auto-cleaned. addAttribute() instead builds URI/query params. Flash attributes are the standard way to show a one-time success message after a redirect.
code
java · 17 lines@PostMapping("/orders")
public String create(OrderForm form, RedirectAttributes ra) {
Order order = service.create(form);
// Invisible, one-shot message that survives the redirect:
ra.addFlashAttribute("message", "Order created");
// Becomes a query param ?tab=summary :
ra.addAttribute("tab", "summary");
// 302 -> browser GETs /orders/42?tab=summary (PRG pattern)
return "redirect:/orders/" + order.getId();
}
@GetMapping("/orders/{id}")
public String show(@PathVariable Long id, Model model) {
// model already contains "message" from the flash map on this request
model.addAttribute("order", service.find(id));
return "orders/show";
}go deeper
Knows redirect sends the browser elsewhere; may not know forward or flash attributes.
Must distinguish redirect (new request/302) vs forward (same request) and use addFlashAttribute for PRG messages.
Explains FlashMap/FlashMapManager storage, query-param exposure of model attrs, and 302 vs 303 nuance.
Reasons about PRG as an idempotency/UX pattern and the session dependency of flash storage in a clustered deployment.
## Two special prefixes When a controller returns a view name, Spring first checks for reserved prefixes before handing the name to a `ViewResolver`: - **`redirect:`** — e.g. `return "redirect:/orders/42";`. Spring creates a `RedirectView` that sends an HTTP redirect status (302 by default, 303 See Other when configured) with a `Location` header. The **browser makes a completely new request** to the target URL. This is a client round-trip; the URL in the address bar changes. - **`forward:`** — e.g. `return "forward:/internal/handler";`. Spring uses the servlet `RequestDispatcher` to **forward server-side** within the *same* HTTP request. No round trip, the browser never knows, the URL stays the same. ## Why redirect matters: Post/Redirect/Get (PRG) After a successful `POST` (create an order, submit a form), returning a normal view means the rendered page is the response to the POST. If the user hits refresh, the browser re-submits the POST — duplicate order. The fix is **PRG**: handle the POST, then `return "redirect:/orders/42";`. The follow-up GET is safe to refresh. This is the single most common reason to use `redirect:`. ## The data-loss problem across a redirect A redirect is a new request, so anything in the current request-scoped `Model` is gone. Spring's behavior with `RedirectView`: - Model attributes that are simple values get **appended to the redirect URL as query parameters** by default (you can disable this). That exposes data in the URL and browser history — bad for messages or sensitive values. - `@PathVariable` placeholders in the redirect string are expanded from the model too: `"redirect:/orders/{id}"`. ## Flash attributes — the clean solution Declare a `RedirectAttributes` parameter: - `redirectAttributes.addAttribute("page", 2)` → becomes a URI/query param `?page=2`. - `redirectAttributes.addFlashAttribute("message", "Order created")` → stored in **flash storage**, which is session-backed but transient: it survives exactly **one** redirect, is exposed to the target handler's model on the next request, then auto-removed. Perfect for one-time success/error banners. Under the hood `FlashMap` + `FlashMapManager` (session by default) hold the values between the redirecting request and the redirected-to request. ## Gotchas - **Forget flash, use normal model → data vanishes** after redirect. - **Putting big objects / secrets in `addAttribute`** leaks them into the URL. - **`forward:` keeps the same request** — request attributes, the original method, and any already-committed response state carry over; you cannot forward after the response is committed. - **Redirect status**: default 302. For strict PRG semantics use 303; Spring can be told via `RedirectView.setStatusCode` or `setHttp10Compatible(false)`. - **Absolute vs context-relative**: `redirect:/x` is context-relative; `redirect:https://...` is absolute/external. - **Prefixes bypass ViewResolvers entirely** — no template is looked up. ## When to use which - After a mutating POST → `redirect:` (PRG) with `addFlashAttribute` for messages. - To reuse another server-side handler without a round trip (rare in modern apps) → `forward:`.
- Where are flash attributes stored, and how long do they live?They're held in a FlashMap managed by a FlashMapManager (SessionFlashMapManager by default, so effectively the HTTP session). They live across exactly one redirect: written on the redirecting request, merged into the model of the very next request, then removed automatically.
- You return "redirect:/x" but a query param you didn't expect appears in the URL. Why?Simple Model attributes are appended to the RedirectView URL as query parameters by default. Use addFlashAttribute for data you don't want in the URL, or configure the RedirectView / RequestMappingHandlerAdapter to not expose model attributes.
saying these in an interview costs you the question
- Claiming redirect and forward are the same or interchangeable
- Saying you can pass the current Model through a redirect unchanged
- Thinking addAttribute hides the value (it becomes a query param)
- Returning a normal view after POST and not understanding duplicate-submit risk