Skip to content

跨域

1. 什么是跨域?为什么会有跨域限制?

答案:跨域是指在浏览器中,当前页面的脚本试图访问不同源(协议、域名、端口三者有任一不同)的资源时受到的限制。

跨域限制的主要原因是安全考虑,它是浏览器的同源策略的一部分,用于防止恶意脚本访问其他网站的敏感数据。

2. 常见的跨域解决方案有哪些?

答案:常见的跨域解决方案包括:

  1. CORS(跨域资源共享)
  2. JSONP
  3. 代理服务器
  4. postMessage
  5. WebSocket
  6. document.domain + iframe
  7. 浏览器插件(如Chrome的Allow-Control-Allow-Origin)

3. 什么是CORS?如何实现CORS?

答案:CORS(Cross-Origin Resource Sharing,跨域资源共享)是一种基于HTTP头的机制,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。

实现CORS的步骤:

  1. 服务器端设置响应头:
    • Access-Control-Allow-Origin
    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers
  2. 对于非简单请求,服务器需要处理OPTIONS预检请求
  3. 客户端无需特殊设置,使用普通AJAX即可

示例(Node.js + Express):

javascript
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

4. JSONP的原理是什么?如何实现JSONP?

答案:JSONP(JSON with Padding)利用了<script>标签不受同源策略限制的特性。它通过动态创建script标签,向服务器请求数据,服务器返回一个函数调用,这个函数调用的参数就是我们需要的数据。

实现JSONP的步骤:

  1. 客户端定义一个回调函数
  2. 创建<script>标签,src指向接口地址,并带上回调函数名
  3. 服务器接收到请求后,将数据作为参数和函数名拼接成函数调用的形式返回

示例:

javascript
// 客户端
function handleResponse(data) {
    console.log(data);
}
const script = document.createElement('script');
script.src = 'http://example.com/api?callback=handleResponse';
document.body.appendChild(script);

// 服务器端(Node.js)
app.get('/api', (req, res) => {
    const data = {name: 'John', age: 30};
    const callback = req.query.callback;
    res.send(`${callback}(${JSON.stringify(data)})`);
});

5. 什么是预检请求(Preflight Request)?什么情况下会触发预检请求?

答案:预检请求是在某些跨域请求前,浏览器自动发起的 OPTIONS 请求,用于检查实际请求是否可以安全地发送。

触发预检请求的情况:

  1. 使用了以下HTTP方法之一:PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH
  2. 人为设置了以下集合之外首部字段:Accept、Accept-Language、Content-Language、Content-Type
  3. Content-Type 的值不属于以下之一:application/x-www-form-urlencoded、multipart/form-data、text/plain

6. 如何使用postMessage实现跨域通信?

答案:postMessage是HTML5引入的API,可以安全地实现跨源通信。

使用步骤:

  1. 在发送方使用 targetWindow.postMessage(message, targetOrigin) 发送消息
  2. 在接收方使用 window.addEventListener('message', handler) 监听消息

示例:

javascript
// 发送方(http://example.com)
const iframe = document.getElementById('myIframe');
iframe.contentWindow.postMessage('Hello from example.com', 'http://target.com');

// 接收方(http://target.com)
window.addEventListener('message', (event) => {
    if (event.origin !== 'http://example.com') return;
    console.log('Received message:', event.data);
});

7. 什么是CORS预检请求?如何优化CORS预检请求?

答案:CORS预检请求是一种OPTION请求,用于检查实际请求是否可以安全地发送。

优化CORS预检请求的方法:

  1. 使用Access-Control-Max-Age头部缓存预检请求结果
  2. 减少非简单请求:尽可能使用简单请求(GET、POST、HEAD)
  3. 合并多个请求以减少预检请求的次数
  4. 在服务器端正确处理OPTIONS请求

示例(设置预检请求缓存时间):

javascript
res.header('Access-Control-Max-Age', '86400'); // 缓存预检请求结果24小时

8. 如何在Node.js中实现CORS中间件?

答案:在Node.js中,可以使用Express框架并实现一个CORS中间件:

javascript
function corsMiddleware(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

  // 处理 OPTIONS 请求
  if ('OPTIONS' === req.method) {
    res.sendStatus(200);
  } else {
    next();
  }
}

app.use(corsMiddleware);

9. 跨域资源共享(CORS)的安全隐患有哪些?如何防范?

答案:CORS的安全隐患主要包括:

  1. 过于宽松的Access-Control-Allow-Origin设置
  2. 错误的凭证处理
  3. 不安全的响应暴露

防范措施:

  1. 严格限制Access-Control-Allow-Origin,避免使用通配符 *
  2. 谨慎处理Access-Control-Allow-Credentials
  3. 使用Access-Control-Expose-Headers限制暴露的响应头
  4. 正确配置Access-Control-Allow-Methods和Access-Control-Allow-Headers
  5. 实施内容安全策略(CSP)

10. 什么是子域名跨域?如何解决子域名跨域问题?

答案:子域名跨域是指在同一主域名下的不同子域名之间的跨域问题,例如 sub1.example.com 和 sub2.example.com 之间的通信。

解决方法:

  1. 使用document.domain:
    javascript
    document.domain = 'example.com';
  2. 使用postMessage
  3. 使用CORS
  4. 使用代理服务器
  5. 使用 jsonp
  6. 使用 window.name

注意:document.domain方法只适用于二级域名相同的情况,且存在安全风险,应谨慎使用。