浏览器跨域问题与四种解决方法

前言

众所周知,现在开发项目都是使用的前后端分离的项目,而我们在使用前后端分离项目去调接口的时候都会产生这个跨越的问题,但这主要还是因为浏览器出于这个安全策略的考虑,帮我们做了这个同源策略。

1.为什么会产生跨越 ?

首先了解一下同源策略:同源策略、是一种约定,是浏览器最核心也会最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSSCSRF等攻击。所谓同源是指“协议+端口+域名”三者相同;即使是三者中有一个不同就会产生这个跨越的问题。

首先我们来看一个小例子:

主机(www.xiaopeng.com) 是否产生跨越 原因
www.xiaopeng.com 协议不同 http 和 https
www.xiaopeng.com:8001 端口协议不同 80 和 8001
www.baidu.com 域名不同 xiaopeng 和 baidu
www.xiaopeng.com/index.html 协议+端口+域名 三者相同

2.解决跨越的方法

2.1 前后端协商jsonp

jsonp解决跨越的原理也比较简单,因为在JSscript标签的src是不受同源策略的限制,也就是说可以跨越请求数据。但是这个script标签的src请求数据也有一个缺点,就是只能发送get请求;虽然说可以解决跨越,但是安全性上面就没有安全可言了哈。而使用jsonp时对于后端来说它返回的是一个函数对,而不是一个字符串也不是一个json。所以说在前端时要提前把这个函数给定义好。等返回时它就会把这个值注入到函数的参数里面,此时将实现了跨域的访问,也就是拿到了后端返回过来的值。

前端实例代码:

// 定义一个handleResponse函数,用于处理返回的数据
function handleResponse(data) {
  // 在这里处理返回的数据
}
// 创建一个新的script元素,并设置其src属性为API的URL。URL中的callback参数值为handleResponse
// 这是服务器端将返回的数据作为handleResponse函数的参数
let script = document.createElement('script');
script.src = 'http://example.com/api?callback=handleResponse';
// 将这个script元素添加到文档的head中。这将触发浏览器去加载并执行这个脚本,从而发送请求到服务器
document.head.appendChild(script);

后端实例代码,以nodejs为例:

// 当你向 /api 发送 GET 请求时,这个函数会被调用。
// req 是一个包含请求信息的对象,res 是一个用于构建响应的对象
app.get('/api', (req, res) => {
  // 首先创建 data 的对象,其中包含一个消息 "Hello, world!"
  const data = { message: 'Hello, world!' };
  // 从请求的查询参数中获取 callback 参数。查询参数是 URL 中 ? 后面的部分,
  // 例如 /api?callback=myFunction
  const callback = req.query.callback;
  // 将 callback 和 data 一起发送回客户端。data 对象被转换为 JSON 格式,
  // 然后被插入到 callback 函数调用中。这是 JSONP(JSON with Padding)的一种实现方式,
  // 它允许跨域请求
  res.send(`${callback}(${JSON.stringify(data)})`);
});
2.2 前端解决使用代理dev

在开发环境中,我们可以通过配置代理服务器来实现跨域请求。通过设置一个代理服务器将前端的请求转发到目标服务器上,绕过浏览器的同源策略限制,从而解决跨域问题。这种方法对于前端开发人员来说比较便捷,无需对后端进行任何修改。

在一般的前端项目中,我们可以使用工具如webpack-dev-serverhttp-proxy-middleware等来快速设置代理服务器。

配置示例(webpack.config.js):

module.exports = {
  // 其他配置项...
  devServer: {
    proxy: {
      // /api表示需要代理的URL路径,可以根据具体情况进行修改
      '/api': {
        // target表示目标服务器的地址,即需要发送请求的真实服务器地址。
        // 开发环境中一般是后端API服务器的地址
        target: 'http://example.com', // 目标服务器的地址
        // changeOrigin设置为true,会更改请求头中的Host字段为目标URL的主机部分,
        // 以便于服务器正确处理请求
        changeOrigin: true // 设置为true,将请求头中的Host字段更改为目标URL的主机部分
      }
    }
  }
};

配置完成后,当前端代码中发送的请求路径匹配到了/api路径时,webpack-dev-server就会将请求通过代理服务器转发到目标服务器上,避免了浏览器的跨域限制。目标服务器处理完请求后,将响应返回给代理服务器,再由代理服务器将响应返回给前端。

前端代码示例(使用fetch函数):

fetch('/api/data')
  .then(response => response.json())
  .then(data => {
    // 在这里处理返回的数据
  })
  .catch(error => {
    // 错误处理
  });

在上述示例中,我们使用了fetch函数发送了一个GET请求到/api/data路径。由于配置了代理服务器,实际发送的请求将会被转发到example.com/api/data地址上。获取到响应后,我们可以对返回的数据进行处理。

通过前端设置代理服务器,我们可以使得跨域请求在开发环境中变得更加简单和方便。同时,这种方法不会涉及到后端代码的修改,适用于前端开发人员快速解决跨域问题的场景。需要注意的是,在生产环境中,代理服务器的设置应该由运维人员来负责,并且不建议将代理服务器用于生产环境。

2.3 后端设置请求头

在解决跨域问题时,后端可以通过设置响应头来允许特定的跨域请求。通过在响应中添加特定的头部信息,告知浏览器该请求是可以被跨域访问的。这种方法比较灵活,因为可以根据具体的需求设置允许的请求来源、方法和头部信息。

后端代码示例(以Node.js和Express框架为例):

// 通过res.setHeader方法来设置响应头的相关属性
app.use((req, res, next) => {
  // Access-Control-Allow-Origin:允许特定来源的跨域请求,可以使用通配符 * 允许所有来源
  res.setHeader('Access-Control-Allow-Origin', 'http://example.com'); 
  // Access-Control-Allow-Methods:指定允许跨域请求的方法,多个方法使用逗号分隔
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); 
  // Access-Control-Allow-Headers:指定允许的跨域请求头部信息,多个头部使用逗号分隔
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); 
  // Access-Control-Allow-Credentials:指定是否允许发送跨域请求的凭证,
  // 例如 Cookie。如果需要发送凭证,则设置为true
  res.setHeader('Access-Control-Allow-Credentials', 'true'); 

  next();
});

通过在后端设置相应的响应头信息,浏览器就会根据这些信息来判断是否允许跨域访问,并在允许的情况下将请求的结果返回给前端。

需要注意的是,对于某些自定义的请求头部信息,如Authorization,需要在Access-Control-Allow-Headers中进行明确的设置,才能被浏览器允许跨域访问。另外,如果前端请求中包含了凭证,例如发送了 Cookie,需要设置Access-Control-Allow-Credentialstrue才能成功发送跨域请求。

通过以上后端设置请求头的方式,可以灵活地控制允许的跨域请求来源、方法和头部信息,从而解决浏览器跨域问题。请根据自己的具体需求进行相应的配置。

2.4 运维段解决nginx代理

在生产环境中,常用的服务器软件Nginx可以作为反向代理服务器来解决跨域问题。通过在Nginx的配置中添加相应的反向代理规则,可以实现跨域请求的转发。

配置示例(nginx.conf):

http {
  # 其他配置项...
  
  server {
    listen 80;
    // example.com是你的域名,需要替换为实际的域名
    server_name example.com; 
    // /api/表示需要进行反向代理的路径,可以根据具体情况进行修改
    location /api/ {
      // proxy_pass指定了目标服务器的地址,即需要代理到的真实服务器地址
      proxy_pass http://target-server/;
      
      # 可选项:设置请求头部
      // proxy_set_header用于设置请求头部信息。
      // 需要根据实际需求设置相关的头部信息,
      // 例如X-Real-IP用于设置真实客户端的IP地址,Host用于设置目标服务器的主机名
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $http_host;
    }
  }
}

完成以上配置后,当有请求路径匹配到了/api/时,Nginx会将请求转发到目标服务器上,并将代理服务器收到的响应返回给客户端。

需要注意的是,上述配置示例只是基础的示范,具体的配置可能会因为实际环境和需求的不同而有所差异。你需要根据自己的实际情况进行相应的配置,例如修改域名、路径和代理目标等。另外,Nginx还有更多的高级配置选项和优化策略可以用于实际生产环境中。

通过运维人员的设置,使用Nginx作为反向代理服务器可以实现跨域请求的转发,并在生产环境中有效地解决跨域问题。这种方式将跨域请求的处理逻辑集中在服务器端,对于前端开发人员而言更加方便和透明。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYzCl4Rz' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片