MST
星途 面试题库

面试题:Next.js静态资源安全访问控制中如何应对跨域问题

假设你的Next.js应用需要从不同域名获取静态资源,且要保证安全访问控制,描述你会采取哪些措施来处理跨域问题并同时维护资源的安全访问,包括可能涉及的配置和代码实现。
11.9万 热度难度
前端开发Next.js

知识考点

AI 面试

面试题答案

一键面试

1. CORS(跨域资源共享)

  • 服务器端配置:在服务器端,设置允许跨域的请求头。例如在Node.js中使用Express框架:
const express = require('express');
const app = express();

// 允许所有来源的请求(生产环境需替换为具体域名)
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  next();
});

// 其他路由和中间件
app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在实际生产中,Access-Control-Allow-Origin 应设置为具体的允许的域名,如 res.setHeader('Access-Control-Allow-Origin', 'https://example.com')

2. 使用代理

  • Next.js配置:在Next.js项目中,可以通过 next.config.js 文件配置代理。首先安装 http-proxy-middleware
npm install http-proxy-middleware

然后在 next.config.js 中进行如下配置:

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'https://external-domain.com/api/:path*', // 目标跨域地址
      },
    ];
  },
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Access-Control-Allow-Credentials',
            value: 'true',
          },
          {
            key: 'Access-Control-Allow-Origin',
            value: 'https://your-client-domain.com',
          },
          {
            key: 'Access-Control-Allow-Methods',
            'GET,OPTIONS,PATCH,DELETE,POST,PUT',
          },
          {
            key: 'Access-Control-Allow-Headers',
            value:
              'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version',
          },
        ],
      },
    ];
  },
};

这样,所有对 /api 开头的请求都会被代理到 https://external-domain.com/api,并且设置了相应的CORS头。

3. JSONP(仅适用于GET请求)

  • 前端代码实现:如果资源提供方支持JSONP,可以在前端这样实现:
function loadScript(src, callback) {
  const script = document.createElement('script');
  script.src = src;
  script.onload = callback;
  document.head.appendChild(script);
}

// 假设跨域接口为 https://external-domain.com/api/data?callback=jsonpCallback
loadScript('https://external-domain.com/api/data?callback=jsonpCallback', () => {
  // jsonpCallback函数会在脚本加载后执行
  function jsonpCallback(data) {
    console.log('Received data:', data);
  }
});

但JSONP有局限性,只能处理GET请求,并且安全性依赖于资源提供方的实现。

4. 身份验证和授权

  • Token验证:无论使用哪种跨域方法,都应该结合身份验证机制,如JWT(JSON Web Token)。在前端请求时,将JWT包含在请求头中:
const headers = {
  'Authorization': `Bearer ${localStorage.getItem('token')}`,
};
fetch('https://external-domain.com/api/data', { headers })
 .then(response => response.json())
 .then(data => console.log(data));

在服务器端验证JWT的有效性,只有通过验证的请求才能访问资源。

const jwt = require('jsonwebtoken');
const secret = 'your-secret-key';

app.use((req, res, next) => {
  const token = req.headers['authorization'];
  if (token) {
    const parts = token.split(' ');
    if (parts.length === 2 && parts[0] === 'Bearer') {
      jwt.verify(parts[1], secret, (err, decoded) => {
        if (err) {
          return res.status(401).json({ message: 'Unauthorized' });
        }
        req.user = decoded;
        next();
      });
    } else {
      return res.status(401).json({ message: 'Invalid token' });
    }
  } else {
    return res.status(401).json({ message: 'No token provided' });
  }
});