外部网页指定DIV加载需求:多账号预约时仅刷新日历DIV
Alright, let's break down your two requirements with practical, actionable solutions that account for real-world constraints like CORS and session isolation:
Grabbing a single DIV from an external site boils down to handling cross-origin restrictions and extracting the right element. Here are your options:
Direct Fetch (Same Origin or CORS-Enabled)
If the external site allows cross-origin requests (via CORS headers), you can use the browser'sfetchAPI to grab the full HTML, then yank out the DIV you need:async function loadExternalDiv(externalUrl, targetSelector, containerId) { try { const response = await fetch(externalUrl); if (!response.ok) throw new Error(`Failed to load: ${response.status}`); const rawHtml = await response.text(); // Create a temporary container to parse the HTML const tempContainer = document.createElement('div'); tempContainer.innerHTML = rawHtml; // Extract the target DIV const targetDiv = tempContainer.querySelector(targetSelector); if (targetDiv) { // Replace your page's container with the external DIV document.getElementById(containerId).replaceWith(targetDiv); } else { console.error(`Couldn't find element matching ${targetSelector} in external page`); } } catch (err) { console.error('Error loading external DIV:', err); } } // Example usage: Load #appointment-calendar from external-site.com into your #local-container loadExternalDiv('https://external-site.com/book', '#appointment-calendar', 'local-container');Note: This will fail if the external site doesn't explicitly allow your domain via CORS headers—browsers block cross-origin requests by default for security.
Backend Proxy Workaround (CORS-Restricted Sites)
If the external site blocks CORS, you'll need a simple backend proxy to fetch the HTML on your behalf (since server-side requests aren't bound by browser CORS rules). Here's a quick Node.js/Express example:const express = require('express'); const fetch = require('node-fetch'); const app = express(); // Proxy endpoint to fetch external HTML app.get('/proxy', async (req, res) => { try { const externalUrl = req.query.url; const response = await fetch(externalUrl); const html = await response.text(); res.send(html); } catch (err) { res.status(500).send('Proxy failed to fetch external content'); } }); app.listen(3000, () => console.log('Proxy running on port 3000'));Then update your frontend to use the proxy:
loadExternalDiv('http://localhost:3000/proxy?url=https://external-site.com/book', '#appointment-calendar', 'local-container');
This is trickier because each user needs an independent login session, and you want to avoid full page reloads. Here are two solid approaches:
Isolate Sessions with iFrames
Each user gets their own hidden iframe, which maintains its own cookie-based session. You can then interact with the iframe's DOM to log in users and refresh only the calendar DIV:- Set up iFrames for each user
<!-- Hidden iframes to hold each user's session --> <iframe id="user1-session" src="https://booking-site.com/login" style="display: none;"></iframe> <iframe id="user2-session" src="https://booking-site.com/login" style="display: none;"></iframe> - Auto-login each user
async function loginUser(iframeId, username, password) { const iframe = document.getElementById(iframeId); // Wait for the login page to load await new Promise(resolve => iframe.onload = resolve); const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // Fill and submit the login form (adjust selectors to match the booking site) const loginForm = iframeDoc.querySelector('#login-form'); loginForm.querySelector('#username-input').value = username; loginForm.querySelector('#password-input').value = password; loginForm.submit(); // Wait for post-login redirect await new Promise(resolve => iframe.onload = resolve); console.log(`User logged in via ${iframeId}`); } // Log in two users loginUser('user1-session', 'user1@example.com', 'user1pass'); loginUser('user2-session', 'user2@example.com', 'user2pass'); - Refresh only the calendar DIV
Instead of reloading the entire iframe, fetch the latest calendar HTML via your proxy and replace the existing calendar in the iframe:async function refreshUserCalendar(iframeId, calendarSelector) { const iframe = document.getElementById(iframeId); const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // Fetch the latest page content via proxy const proxyUrl = `http://localhost:3000/proxy?url=${encodeURIComponent(iframe.src)}`; const response = await fetch(proxyUrl); const rawHtml = await response.text(); // Extract the fresh calendar const tempContainer = document.createElement('div'); tempContainer.innerHTML = rawHtml; const freshCalendar = tempContainer.querySelector(calendarSelector); if (freshCalendar) { // Replace the old calendar in the iframe const existingCalendar = iframeDoc.querySelector(calendarSelector); existingCalendar.replaceWith(freshCalendar); } else { console.error(`Calendar selector ${calendarSelector} not found`); } } // Refresh user1's calendar refreshUserCalendar('user1-session', '#booking-calendar');
Caveats: You'll need to know the exact selectors for the login form and calendar on the external site. Also, some sites use anti-bot measures (like CAPTCHAs) that will block automated logins.
- Set up iFrames for each user
Session Management via Backend Cookie Jars
For more control, use a backend to manage separate cookie jars for each user. This avoids iFrames but requires more backend work:- Backend with cookie jar storage (Node.js example)
const express = require('express'); const fetch = require('node-fetch'); const { CookieJar } = require('tough-cookie'); const app = express(); app.use(express.json()); // Store cookie jars per user ID const userSessions = new Map(); // Endpoint to log in a user and store their session cookie app.post('/api/login', async (req, res) => { const { userId, username, password } = req.body; const jar = new CookieJar(); // First, fetch the login page to get initial cookies (like CSRF tokens) await fetch('https://booking-site.com/login', { jar }); // Submit login credentials await fetch('https://booking-site.com/submit-login', { method: 'POST', jar, body: new URLSearchParams({ username, password }), headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); userSessions.set(userId, jar); res.status(200).send('Login successful'); }); // Endpoint to fetch the latest calendar for a user app.get('/api/calendar', async (req, res) => { const { userId, calendarUrl } = req.query; const jar = userSessions.get(userId); if (!jar) return res.status(401).send('User not logged in'); const response = await fetch(calendarUrl, { jar }); const rawHtml = await response.text(); // Extract and send only the calendar DIV const tempContainer = document.createElement('div'); tempContainer.innerHTML = rawHtml; const calendar = tempContainer.querySelector('#booking-calendar'); res.send(calendar ? calendar.outerHTML : 'Calendar not found'); }); app.listen(3000, () => console.log('Backend running on port 3000')); - Frontend to trigger login and refresh
// Log in a user async function loginUser(userId, username, password) { await fetch('http://localhost:3000/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId, username, password }) }); } // Refresh a user's calendar and update the page async function refreshCalendar(userId, calendarUrl, containerId) { const response = await fetch(`http://localhost:3000/api/calendar?userId=${userId}&calendarUrl=${encodeURIComponent(calendarUrl)}`); const calendarHtml = await response.text(); document.getElementById(containerId).innerHTML = calendarHtml; } // Usage loginUser('user1', 'user1@example.com', 'user1pass'); // Later, refresh the calendar refreshCalendar('user1', 'https://booking-site.com/calendar', 'user1-calendar');
Note: You may need to handle CSRF tokens explicitly—some sites require a token from the login page to be included in the login POST request.
- Backend with cookie jar storage (Node.js example)
内容的提问来源于stack exchange,提问作者user9746696

