没有人比我更懂跨域!!!

概念介绍

        跨域是由于浏览器的同源策略所导致的一种安全机制。同源策略要求网页在发送网络请求时,api的协议、域名、端口必须与网页完全相同,否则浏览器就会阻止这些请求,这就是跨域限制。

        跨域是浏览器特有的一种特性,在服务端并不存在跨域的概念。服务器之间进行通信时,只要网络可达、权限允许,就可以自由地交互数据。

开发环境设置跨域

        由于跨域是浏览器所特有,在服务器上不存在跨域。基于这样的原理,可以利用 Vite 内置的服务模块来设置代理,以此巧妙地绕过跨域限制。当前端需要向不同源的api发起请求时,Vite 内置的HTTP服务就开始发挥作用了。

        开发环境下,axios请求会先发送到 Vite 启动的本地开发服务器( 提供localhost服务的server),而不是直接发送到真实地址。然后,开发服务器会根据我们预先配置好的代理规则,将这个请求转发到对应的后端服务器。预先配置好的代理规则可以如下。

// vite.config.ts  配置
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8083',
        //转发时改变header中的Origin,使其与后端源(http://localhost:8083)相匹配
        changeOrigin: true, 
        //用正则将请求路径开头的'/api'替换为空(修正为真实的api地址)
        rewrite: (path) => path.replace(/^\/api/, "")
      }
    }
  },
});

axios配置

import axios, { AxiosInstance } from "axios";

const service: AxiosInstance = axios.create({
    baseURL: import.meta.env.VITE_BASE_URL,
    timeout: 12000
});
// 开发环境:VITE_BASE_URL="/api"
// 生产环境:VITE_BASE_URL="http://domain:port"

基于以上配置,当本地服务器收到以'/api'开头的请求时,会将该请求转发到localhost:8083 ,即真实的后端地址。

比如,axios发起请求http://localhost:5173/api/users,Vite 会将这个请求代理到 http://localhost:8083/users,并修改Header中的 Origin,同时对请求路径调整,确保请求能够被后端正确处理。

       这也是为什么开发环境下的请求地址都是http://localhost:5173/api/xxx,而非真实后端端口。

生产环境设置跨域

一、Spring的CorsFilter

       浏览器通常会因为同源策略限制这种交互,除非服务器明确允许。而服务器明确允许指的就是CORS

       跨域资源共享机制(CORS)允许服务器向浏览器声明哪些跨域请求是允许的。它通过服务器在响应头中添加特定的信息来实现,当浏览器看到这些信息,就会允许相应的跨域请求。

特定的信息包括:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Credentials
  • Access-Control-Max-Age
  • Access-Control-Expose-Headers

Access-Control-Allow-Origin:指定服务器允许的请求源(Origin),可以是一个或多个源( http://xxx.com),也可以是 * 允许任何源,但是*不安全。

Access-Control-Allow-Methods指定允许的 HTTP 请求方法,包括 GETPOSTPUTDELETEOPTIONS 等。

Access-Control-Allow-Headers指定允许的请求头。可以是具体的请求头列表,也可以是 * 表示允许任何请求头(不安全)。

Access-Control-Allow-Credentials指定是否允许请求前端携带凭证,如 cookie、HTTP 认证信息等。只能为true或false;为true时第一个字段值不能为*。

Access-Control-Max-Age指定 OPTIONS 请求的缓存时长。在这个时长内,浏览器会使用缓存的预检请求结果,而不是每次都发送预检请求。指定 OPTIONS 请求的缓存时长。

Access-Control-Expose-Headers指定哪些响应头可以暴露给浏览器。

       例如,当浏览器发起一个跨域的 POST 请求时,浏览器会先检查响应中的 Access-Control-Allow-Origin 是否包含请求的源,Access-Control-Allow-Methods 是否包含 POST 方法,Access-Control-Allow-Headers 是否包含请求的请求头,以及其他相关信息......如果不满足,浏览器会阻止请求,并可能抛出一个错误。

       跨域问题仅靠前端无法解决(前端仔泪目😭),需要后端配置。通过以下过滤器可以在服务器端添加相应的响应头,以允许跨域请求。CORS 机制中,当网页需要发送一个跨域的请求时,浏览器会在真实发送之前,先发送一个 OPTIONS 请求询问服务器是否允许真实请求

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CorsFilter implements Filter {
    // 先执行过滤器,后执行拦截器
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        String origin = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", origin);
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, Origin, X-Requested-With, cache-control, pragma, proxy-connection, User-Agent");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        //if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
        //  response.setStatus(HttpServletResponse.SC_OK);
        //  return;
        //}
        chain.doFilter(req, res);
    }

}

       前端只要满足上述配置,请求方法只有GET、POST、OPTIONS,不包括PUT啦,DELETE啦,以及不添加一些奇奇怪怪的请求头啦,是可以进行跨域的~~

       (注释的方法很作弊,直接对所有的OPTIONS返回ok,我就是这么干的

       浏览器会检查预检响应头是否包含特定字段,以决定继续请求或是丢弃响应结果。

二、Nginx 反向代理

       生产环境无法设置开发代理,但是可以设置Nginx 反向代理。Nginx 可以作为中间层将客户端请求转发到后端,并添加跨域头。

server {
    listen 80;
    server_name xxx.com;

    location / {
        if ($request_method = 'OPTIONS') {
            # 设置允许的源仅允许 https://xxx.com
            add_header 'Access-Control-Allow-Origin' 'https://xxx.com';
            # 允许的方法
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            # 允许的请求头
            add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
            # 是否允许携带凭证
            add_header 'Access-Control-Allow-Credentials' 'true';
            # 对于OPTIONS,返回 204 No Content
            return 204;
        }
        # 将请求转发到后端服务
        proxy_pass http://xxx:yyy;
    }
}

以上配置Nginx 会对 OPTIONS 做特殊处理,添加跨域头,然后将请求转发到后端(http://xxx)。这样可以将跨域问题从后端分离出来,由 Nginx 进行统一处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值