会话超时后如何重定向至自定义页面?
Got it, let's fix this session redirect issue for you. It sounds like your current setup is sending users back to the index page when their session times out, but you want them landing on your custom expired page instead. Here's how to tackle this depending on your tech stack and how you're handling session timeouts:
1. Configure in web.xml (for Java EE/JSF apps)
Since your login link points to index.xhtml, I'm guessing you're working with a JSF or Java EE-based app. This is the most straightforward server-side fix:
- Open your
web.xmlconfiguration file - Add or update the
<session-config>section to map session timeout errors to your custom page:
<session-config> <session-timeout>30</session-timeout> <!-- Set your timeout in minutes --> <error-page> <error-code>401</error-code> <!-- Catches unauthorized access from expired sessions --> <location>/session-expired.html</location> <!-- Path to your custom page --> </error-page> <error-page> <exception-type>javax.faces.application.ViewExpiredException</exception-type> <location>/session-expired.html</location> <!-- Handles JSF-specific view state expiration --> </error-page> </session-config>
2. Handle Session Timeout with Frontend JavaScript
If you're using client-side logic to track user inactivity, update your timeout handler to redirect to your custom page instead of index:
// Example inactivity timer let inactivityTimer; function resetTimer() { clearTimeout(inactivityTimer); // Set timeout to match your session duration (30 minutes = 1800000 ms) inactivityTimer = setTimeout(() => { window.location.href = '/session-expired.html'; // Redirect to your custom page }, 1800000); } // Reset timer on user interactions document.addEventListener('mousemove', resetTimer); document.addEventListener('keypress', resetTimer); document.addEventListener('click', resetTimer);
Just make sure the path to session-expired.html matches where you've placed the file in your project.
3. Server-Side Session Check (JSF Managed Bean)
Add a session validation check in your server-side beans to redirect expired sessions:
@ManagedBean @SessionScoped public class SessionValidator implements Serializable { public void checkSessionValidity() { FacesContext context = FacesContext.getCurrentInstance(); HttpSession session = (HttpSession) context.getExternalContext().getSession(false); if (session == null || !context.getExternalContext().isUserInRole("authenticated")) { try { context.getExternalContext().redirect("/session-expired.html"); } catch (IOException e) { e.printStackTrace(); } } } }
Then call this method when your protected pages load:
<f:event type="preRenderView" listener="#{sessionValidator.checkSessionValidity}" />
Quick Checks to Ensure It Works
- Confirm your
session-expired.htmlis placed in the correct root directory of your web app (or adjust the path in your config if it's in a subfolder like/pages/session-expired.html). - Make sure your application server isn't overriding redirect behavior (some servers have default session timeout redirects you may need to disable).
Here's your custom session expired page code, formatted for reference:
<!DOCTYPE html> <html> <head> <title>Session Expired</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <style type="text/css"> html { font-family: sans-serif; line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100% } body { margin: 0 } article, aside, footer, header, nav, section { display: block } h1 { font-size: 2em; margin: .67em 0 } figcaption, figure, main { display: block } figure { margin: 1em 40px } hr { box-sizing: content-box; height: 0; overflow: visible } pre { font-family: monospace, monospace; font-size: 1em } a { background-color: transparent; -webkit-text-decoration-skip: objects } a:active, a:hover { outline-width: 0 } abbr[title] { border-bottom: none; text-decoration: underline; text-decoration: underline dotted } b, strong { font-weight: inherit } b, strong { font-weight: bolder } code, kbd, samp { font-family: monospace, monospace; font-size: 1em } dfn { font-style: italic } mark { background-color: #ff0; color: #000 } small { font-size: 80% } sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline } sub { bottom: -.25em } sup { top: -.5em } audio, video { display: inline-block } audio:not([controls]) { display: none; height: 0 } img { border-style: none } svg:not(:root) { overflow: hidden } button, input, optgroup, select, textarea { font-family: sans-serif; font-size: 100%; line-height: 1.15; margin: 0 } button, input { overflow: visible } button, select { text-transform: none } [type=reset], [type=submit], button, html [type=button] { -webkit-appearance: button } [type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner { border-style: none; padding: 0 } [type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring { outline: 1px dotted ButtonText } fieldset { border: 1px solid silver; margin: 0 2px; padding: .35em .625em .75em } legend { box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal } progress { display: inline-block; vertical-align: baseline } textarea { overflow: auto } [type=checkbox], [type=radio] { box-sizing: border-box; padding: 0 } [type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button { height: auto } [type=search] { -webkit-appearance: textfield; outline-offset: -2px } [type=search]::-webkit-search-cancel-button, [type=search]::-webkit-search-decoration { -webkit-appearance: none } ::-webkit-file-upload-button { -webkit-appearance: button; font: inherit } details, menu { display: block } summary { display: list-item } canvas { display: inline-block } template { display: none } [hidden] { display: none } body, html { width: 100%; height: 100%; background-color: #21232a } body { color: #fff; text-align: center; text-shadow: 0 2px 4px rgba(0, 0, 0, .5); padding: 0; min-height: 100%; -webkit-box-shadow: inset 0 0 75pt rgba(0, 0, 0, .8); box-shadow: inset 0 0 75pt rgba(0, 0, 0, .8); display: table; font-family: "Open Sans", Arial, sans-serif } h1 { font-family: inherit; font-weight: 500; line-height: 1.1; color: inherit; font-size: 36px } h1 small { font-size: 68%; font-weight: 400; line-height: 1; color: #777 } a { text-decoration: none; color: #fff; font-size: inherit; border-bottom: dotted 1px #707070 } .lead { color: silver; font-size: 21px; line-height: 1.4 } .cover { display: table-cell; vertical-align: middle; padding: 0 20px } footer { position: fixed; width: 100%; height: 40px; left: 0; bottom: 0; color: #a0a0a0; font-size: 14px } </style> </head> <body> <div class="cover"> <h1>Your session has expired due to inactivity. </h1> <h1> Please login again <a href="index.xhtml">here</a>. Thank you.</h1> </div> </body> </html>
内容的提问来源于stack exchange,提问作者Kareem

