Node.js 代理服务实践:如何优雅解决跨域 API 请求问题?

文摘   2024-10-10 23:18   北京  

关注公众号 前端界,回复“加群

加入我们一起学习,天天进步

前言

在现代 Web 开发中,浏览器的同源策略是一项非常重要的安全机制,它可以有效防止恶意网站未经授权地访问用户的敏感信息。但它同时也给开发者带来了跨域资源请求的难题。尤其是在微前端架构下,不同子应用往往会独立部署在不同域名下,这种跨域限制就会带来 API 调用上的挑战。

本文将详细介绍如何通过 Node.js 代理服务来解决这些问题,帮助你实现跨域 API 请求,确保应用的安全性和兼容性。


为什么需要代理服务?

代理服务器在跨域场景中充当了中介,它使得前端页面只需与同源的代理服务器进行通信,而代理服务器再代为与跨域的 API 进行交互。这样可以有效规避浏览器的跨域限制,同时保证 Cookie 等身份验证信息能够顺利传递给目标服务器。

这种方案应用场景非常广泛,尤其是在以下两个业务环境中:

  1. 微前端架构:每个子应用可能独立部署在不同的域名,但需要与主应用共享登录态。通过代理服务器,子应用可以通过主应用代理访问跨域的 API,解决跨域问题的同时,确保用户身份验证信息(例如 Cookie)能正确传递。

  2. 单页应用(SPA) :客户端可以通过代理服务器访问多个不同域名的 API,而无需担心跨域限制。这在需要调用第三方 API 或微服务架构中十分常见。


实现代理服务的核心流程

整个代理服务的流程可以分为四个步骤:

  1. 客户端请求代理服务器
    客户端发起请求 http://localhost:3000/proxy/data,并携带相关的 Cookie(通过 credentials: 'include' 确保 Cookie 传递)。
  2. 代理服务器接收请求并转发
    代理服务器接收到请求后,会将其转发到目标服务器 https://api.example.com/data,同时传递客户端的 Cookie 到目标服务器,以确保身份验证。
  3. 目标服务器处理请求
    目标服务器根据 Cookie 检查是否存在有效的 sessionId,如果存在有效的会话,则返回用户数据;否则返回未授权错误。
  4. 代理服务器将响应返回客户端
    代理服务器接收目标服务器的响应并将其返回给客户端。

流程图

为了更好地理解整个代理过程,画了一个流程图

image.png

代码实现

1. 代理服务器代码

通过 Node.js 使用 expresshttp-proxy 模块实现一个代理服务器,并确保 Cookie 的正确传递。

const express = require('express');
const httpProxy = require('http-proxy');
const cookieParser = require('cookie-parser');

const app = express();
const proxy = httpProxy.createProxyServer();

// 使用 cookie-parser 中间件解析 Cookie
app.use(cookieParser());

// 代理请求的路由
app.all('/proxy/*', (req, res) => {
  // 假设请求的目标是 https://api.example.com/data
  const targetUrl = `https://api.example.com/${req.params[0]}`;

  // 代理请求的选项,传递 Cookie 和其他必要的请求头
  const options = {
    target: targetUrl,
    changeOrigintrue,  // 使目标服务器看到的请求 Host 是目标服务器而不是代理服务器的 Host
    headers: {
      'Cookie': req.headers.cookie || ''  // 将客户端发送的 Cookie 传递给目标服务器
    }
  };

  // 将请求代理到目标服务器
  proxy.web(req, res, options, (error) => {
    console.error(`Proxy request to ${targetUrl} failed:`, error);
    res.status(500).send('Proxy request failed');
  });
});

// 代理服务启动
app.listen(3000, () => {
  console.log('Proxy server is running on http://localhost:3000');
});
  • cookie-parser 用于解析请求中的 Cookie 并传递给目标服务器。
  • changeOrigin: true 确保目标服务器认为请求直接来自客户端,而非代理服务器。

2. 客户端代码

使用 fetch 方法向代理服务器发起请求,并确保 Cookie 在请求中传递。

fetch('http://localhost:3000/proxy/data', {
  method'GET',
  credentials'include' // 保持 Cookie 在请求中传递
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => console.error('Request failed', err));
  • credentials: 'include' 用于确保浏览器将 Cookie 一并发送到代理服务器。

3. 目标服务器代码

目标服务器处理请求并根据客户端传递的 Cookie 返回相应的数据。

const express = require('express');
const cookieParser = require('cookie-parser');

const app = express();
const port = 8080// 假设目标服务器运行在 8080 端口

// 使用 cookie-parser 中间件解析 Cookie
app.use(cookieParser());

// 模拟的用户数据
const users = {
  'session123': { id1name'前端界'email'xiaoming@163.com' },
  'session456': { id2name'芝士'email'xiaohong@163.com' }
};

// 处理 /data 路由的请求
app.get('/data', (req, res) => {
  const sessionCookie = req.cookies.sessionId;  // 获取请求中的 Cookie,假设叫做 sessionId

  if (!sessionCookie || !users[sessionCookie]) {
    // 如果没有 Cookie 或者 Cookie 不正确,返回 401 未授权
    return res.status(401).json({ error'Unauthorized: Invalid session' });
  }

  // 如果 Cookie 有效,返回该用户的数据
  const userData = users[sessionCookie];
  res.json({
    message'Data fetched successfully',
    user: userData
  });
});

// 启动目标服务器
app.listen(port, () => {
  console.log(`Target server running on http://localhost:${port}`);
});
  • 目标服务器通过 cookie-parser 获取 sessionId,并返回对应的用户数据。
    • 如果 Cookie 无效,则返回 401 未授权错误。

性能优化与安全考虑

缓存机制

代理服务器可以引入缓存机制,减少重复的请求,提升 API 请求性能。常见的方案是使用 redismemory-cache 来缓存目标服务器的响应。

安全性
  • 确保代理服务器使用 HTTPS 协议,防止敏感信息在传输过程中被拦截。
  • 可以对请求和响应的数据进行加密,尤其是在涉及到用户身份验证的场景。
  • 添加 IP 白名单机制,限制哪些客户端可以访问代理服务,避免滥用。

大家好,我是芝士,最近创建了一个低代码/前端工程化交流群,欢迎加我微信 Hunyi32 交流,也可关注我的公众号[ 前端界 ] 持续更新优质技术文章

总结

通过本文的示例,详细讲解了如何使用 Node.js 代理服务来解决跨域 API 请求问题,特别是在微前端架构和单页应用中的应用场景中。代理服务器不仅能够解决跨域问题,还可以确保登录态、Cookie 等关键信息的正确传递。希望这篇文章能帮助小伙伴们在实际开发中顺利解决跨域请求的问题。

最后



大家好,我是芝士,最近创建了一个低代码/前端工程化/高级前端面试交流群,欢迎加我微信,拉你进群,互相监督学习进步等!





关注福利,关注公众号后,在首页:

  • 回复「简历获取精选的简历模板

  • 回复「思维图」获取完整 JavaScript 相关思维图

  • 回复「电子书」可下载我整理的大量前端资源,包含面试、Vue实战项目、CSS和JavaScript电子书等。

  • 回复「Node」获取简历制作建议

最后不要忘了点个赞再走噢

前端界
高质量文章分享、实践干货、技术前沿、学习资料, 你感兴趣的都在前端界
 最新文章