import express from 'express'; import fetch from 'node-fetch'; import cheerio from 'cheerio'; import { URL } from 'url'; const app = express(); const PORT = 7860; function absolutize(base, relative) { try { return new URL(relative, base).toString(); } catch { return relative; } } app.get('/proxy', async (req, res) => { const targetUrl = req.query.url; if (!targetUrl) { return res.status(400).send('Missing ?url= parameter'); } try { const response = await fetch(targetUrl); const contentType = response.headers.get('content-type') || ''; if (contentType.includes('text/html')) { const html = await response.text(); const $ = cheerio.load(html); const base = targetUrl; // 書き換える属性 const attributes = ['href', 'src', 'action']; $('*').each((i, el) => { attributes.forEach(attr => { const val = $(el).attr(attr); if (val && !val.startsWith('data:') && !val.startsWith('javascript:')) { const abs = absolutize(base, val); $(el).attr(attr, `/proxy?url=${encodeURIComponent(abs)}`); } }); }); res.set('Content-Type', 'text/html'); res.send($.html()); } else { // HTML以外はそのままパイプ res.set('Content-Type', contentType); response.body.pipe(res); } } catch (err) { console.error(err); res.status(500).send('プロキシエラー: ' + err.message); } }); app.listen(PORT, () => { console.log(`🌐 Proxy server running at http://localhost:${PORT}`); });