小白理解跨域问题

首先要强调的是,跨域是浏览器引发的问题,其他请求方式如curl、apifox、postman都不会引发跨域问题。记住,跨域是浏览器引发的问题

要理解跨域,得先知道什么是不跨域,这里引发出一个概念,同源

同源:指协议、域名、端口号都相同。记住,是三个都相同,没得商量

一个请求是一个源请求另一个源,当请求源和被请求的源不同时,就是跨域

例如:做了一个前后端分离的项目,前端的端口和后端的端口不同。使用浏览器访问前端页面后,前端需要向后端发起请求。这里因为它们的端口不同,所以这就是一个跨域请求。当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不一同,即跨域。

跨域问题

经过前文的梳理,我们了解了什么是跨域请求,那跨域请求有什么问题吗?有的兄弟,有的。因为浏览器的同源策略,跨域请求得到数据是不给前端用的。注意我这里的措辞,请求得到数据,是的,请求已经发生了,浏览器允许请求发出,是发出请求后,得到的数据检查后不符合不给前端使用(这里有简单请求和复杂请求,就不细分了,有兴趣可以了解一下)

解决跨域问题

解决跨域有两种方法,一种是代理,另一种是CORS。其他方法还有,但是使用少,略过

CORS解决跨域

这种方法是直接的解决跨域问题,这种方法是在后端使用的。浏览器得到请求返回的数据需要检查,检查通过后才给前端使用,那么后端让返回的数据通过检查即可

检查的地方如下(具体不止这些,不要被误导),在响应的响应头上加上对应的响应头即可

Access-Control-Allow-Origin: * // 表明接受什么域名
Access-Control-Allow-Credentials: true // 是否允许发送cookie
Access-Control-Expose-Headers: XXX // 是否暴露其他headers值给前端

例如gin中去解决跨域,加上需要的响应头即可

//允许跨域的中间件
func Cors() gin.HandlerFunc {
  return func(c *gin.Context) {
    method := c.Request.Method
    if c.Request.Header.Get("origin") != "" {
      c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
      c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
      c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
      c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
      c.Header("Access-Control-Allow-Credentials", "true")
    }
    if method == "OPTIONS" {
      c.AbortWithStatus(http.StatusNoContent)
    }
    c.Next()
  }
}

func Index(c *gin.Context) {
  c.JSON(200, gin.H{
    "code": 0,
    "msg":  "成功",
    "data": gin.H{},
  })
  return
}

func main() {
  r := gin.Default()
  r.GET("/api/no_cors", Index)
  r.POST("/api/no_cors", Index)
  r.GET("/api/cors", Cors(), Index)
  r.POST("/api/cors", Cors(), Index)
  r.Run(":8080")
}

可以看到,这种方法就是直接的让浏览器检查,检查通过即可

代理

与上一个的解决思路不同,代理解决跨域问题的核心思路是让请求在浏览器看来是同源的。具体来说,通过在前端和后端之间设置一个代理服务器,隐藏后端真实的源,让浏览器认为请求是同源的,从而绕过同源策略的限制。

这种方案是目前最主流的跨域解决方案,它分为两类,一个是开发环境,一个是生产环境

开发环境解决跨域

以vue3为例,vite提供了代理功能

import {fileURLToPath, URL} from 'node:url'

import {defineConfig, loadEnv} from 'vite'
import vue from '@vitejs/plugin-vue'
import type {ImportMetaEnv} from "./env";
// https://vitejs.dev/config/
export default defineConfig(({mode}) => {
    let env: Record<keyof ImportMetaEnv, string> = loadEnv(mode, process.cwd())

    const serverUrl =  env.VITE_SERVER_URL
    const wsUrl = serverUrl.replace("http", "ws")
    return {
        plugins: [
            vue(),
        ],
        envDir: "./",
        resolve: {
            alias: {
                '@': fileURLToPath(new URL('./src', import.meta.url))
            }
        },
        server: {
            host: "0.0.0.0",
            port: 80,
            proxy: {
                "/api": {
                    target: serverUrl,
                    changeOrigin: true,
                }
            }
        }
    }
})

生产环境解决跨域

使用nginx的反向代理

server {
    listen       80;
    server_name  blog.fengfengzhidao.com;

    location / {
      try_files $uri $uri/ /index.html;  
      root   /opt/gvb/web/dist;
      index  index.html index.htm;
    }

    location /api/ {
      # rewrite ^/(api/.*) /$1 break;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header REMOTE-HOST $remote_addr;
      #反向代理的源
      proxy_pass http://127.0.0.1:8082/api/;
    }
    location /uploads/ {
      alias /opt/gvb/server/uploads/;
    }

    access_log  /opt/gvb/access.log;
    error_log   /opt/gvb/error.log;
}

 文章是借鉴一篇文章彻底搞懂跨域问题再加上本人理解完成的,有兴趣可以看一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值