什么是跨域

报错如下:

同源策略(Same-Origin Policy, SOP)

同源策略(Same-Origin Policy,SOP)是Web浏览器中的一种关键安全机制,旨在限制不同源之间的交互,以保护用户数据的安全和隐私。

域名、协议、端口有一个不同就不是同源,三者均相同,这两个网站就是同源。

1. 跨域网络请求

  • AJAX/Fetch 请求

    • 向不同源的服务器发送 XMLHttpRequest 或 Fetch 请求,若服务器未配置 CORS(跨域资源共享),浏览器会拒绝返回数据。

// 请求不同源的 API
fetch('https://api.other-site.com/data')
  .then(response => response.json())
  .catch(error => console.error('被浏览器拦截'));

2. 跨域资源访问

读取跨域资源内容

  • 通过脚本加载跨域资源(如 JSON 文件、图片、音频),但直接读取内容会被拦截

// 跨域的图片(允许加载,但无法读取像素数据)
const img = new Image();
img.src = 'https://other-site.com/image.jpg';
img.onload = () => {
  canvasContext.drawImage(img, 0, 0);
  canvasContext.getImageData(0, 0, 100, 100); // 报错:画布被污染
};

但也不是所有资源都是要遵守同源策略:

解决跨域

JSONP

JSONP 的核心原理是 通过 <script> 标签加载并执行一段远程代码,是一种“通过代码执行而非数据传输”的跨域方案:

  1. 跨域能力<script> 标签的 src 属性不受同源策略限制。

  2. 代码注入:服务端返回的代码被浏览器当作普通脚本执行,等同于在页面中直接编写的代码。

  3. 数据传递:通过函数调用将数据注入客户端代码。

实现:

<!DOCTYPE html>
<html>
  <body>
    <!-- 定义全局回调函数 -->
    <script>
      window.abc = function (data) {
        console.log(data); // 当JSONP响应加载后触发
      }
    </script>

    <!-- 动态插入JSONP请求 -->
    <script src="http://localhost:8002/jsonp.js?username=xxx&callback=abc"></script>
  </body>
</html>

 等同于

<script>
  window.abc = function (data) {
    console.log(data);
  };
</script>

<script>
  // 直接调用全局函数
  abc({ name: 'xxx' }); // 输出 { name: 'xxx' }
</script>

  • 效果:与 JSONP 完全一致,只是第二个 <script> 的内容由服务端动态生成。 

jQuery实现jsonp

跨域资源共享(CORS)

尽管SOP提供了强有力的安全保障,但它也限制了合法的跨域资源共享需求。为了解决这些问题,Web标准引入了跨域资源共享(CORS)等机制,允许在特定条件下进行跨域交互。CORS是一个W3C标准,允许服务器声明哪些源可以访问其资源,突破了AJAX只能同源使用的限制。

CORS的工作原理

  1. 浏览器检测:当浏览器检测到AJAX请求跨域时,它会自动添加CORS相关的HTTP头信息。这些头信息用于告知服务器请求的源以及请求的性质。(简单请求与非简单请求有不同的HTTP头信息, 详细可见阮一峰的文章)
  2. 服务器响应:服务器需要通过设置适当的CORS响应头来允许跨域请求。常见的CORS响应头包括:
  3. 浏览器处理:如果服务器响应中包含适当的CORS头信息,浏览器将允许跨域请求的响应被JavaScript访问,否则将被拦截。

不同服务器实现例子:

node.js直接配置

const http = require('http');

const port = process.env.PORT || 8000;

const server = http.createServer((request, response) => {
    console.log(`METHOD: ${request.method}; URL: ${request.url}`);

    // 设置CORS头信息
    response.setHeader('Access-Control-Allow-Origin', '*'); // 允许所有源
    response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, DELETE'); // 允许的HTTP方法
    response.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); // 允许的请求头

    if (request.method === 'OPTIONS') {
        // 对于预检请求,直接返回成功响应
        response.writeHead(204);
        response.end();
        return;
    }

    // 处理其他请求
    response.writeHead(200, { 'Content-Type': 'application/json' });
    response.end(JSON.stringify({ message: 'CORS is enabled for this server' }));
});

server.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

 Node.js(Express)

const express = require('express');
const cors = require('cors');
const app = express();

// 使用默认配置允许所有跨域请求
app.use(cors());

// 自定义配置
// app.use(cors({
//   origin: 'http://example.com',
//   methods: 'GET,POST',
//   allowedHeaders: ['Content-Type', 'Authorization']
// }));

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

Apache

httpd.conf.htaccess中添加:

<Directory "/var/www/html">
    Header set Access-Control-Allow-Origin "*"
    Header set Access-Control-Allow-Methods "GET,POST,OPTIONS"
    Header set Access-Control-Allow-Headers "Content-Type"
</Directory>

Nginx

在Nginx配置文件中添加:

location / {
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
    }

    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值