跨域的解决方案

一、概念

1. 浏览器的同源策略

浏览器为确保资源的安全,而遵循的一种策略。

2. 源

源 = 协议 + 域名 + 端口

3. 同源和非同源

当两个源只有他们的协议、域名、端口都一致,才是同源,否则是非同源。

4. 同源请求和非同源请求

如果是同源发出的请求就是同源请求,如果是非同源发出的请求就是非同源请求。

5. 跨域

所处源\] 与 \[目标源\] 不一致,就会导致跨域。 ## 二、浏览器会对跨域做哪些限制 \[源 A\] 和 \[源 B\]是非同源的,则浏览器会有以下限制。 ### 1. DOM 访问限制 \[源 A\]的脚本不能读取和操作\[源 B\]的 DOM ### 2. Cookie 访问限制 \[源 A\]不能访问\[源 B\]的 Cookie ### 3. Ajax 响应数据限制 \[源 A\]可以给\[源 B\]发请求,但无法获取\[源 B\]的返回的数据 ## 三、注意点 跨域限制仅存在浏览器端,服务端不存在跨域限制 即时跨域了,Ajax 请求也可以正常发出,但响应数据不会交给开发者。 \、\、\...这些标签发出的请求也可能跨域,只不过浏览器对标签不做严格限制,对开发几乎无影响。 ## 四、CORS 解决跨域 CORS 即跨源资源共享(Cross-Origin Resource Sharing),CORS 是一种机制,它允许 Web 应用服务器进行跨域访问控制,使不同源的网站之间能够安全地共享资源。 在默认情况下,出于安全考虑,浏览器会限制从一个源(协议、域名、端口)加载的脚本获取或操作另一个源的资源。而 CORS 为 Web 应用提供了一种安全的方式来绕过这种同源策略的限制。 使用 CORS 解决跨域是最正统的方式,且要求服务器是"自己人" ### 1. 简单请求和复杂请求 **简单请求** > **请求方式:**GET、HEAD、POST > > **Content-type:**text/plain、multipart/form-data、application/x-www-form-urlencoded 请求头字段符合《CORS 安全规范》,只要你改了请求头就变复杂请求了。 **复杂请求** 不是简单请求就是复杂请求,复杂请求会自动发送预检请求。 ### 2. 解决简单请求 以 nodeJS 为例,服务器端设置响应头 Access-Control-Allow-Origin,值为发送请求的源表示,只要从这个源发送的请求,都通过。值为 "\\\*" 表示所有不同源发来的请求都通过。 ```javascript app.get("/xxx", (res, req) => { res.setHeader("Access-Control-Allow-Origin", "发送请求源" | "*"); res.send(); }); ``` ### 3. 解决复杂请求 以 nodeJS 为例,服务器设置响应头,与请求头一一对应,使用 cors 插件。 ```javascript app.use( cors({ origin: "xxx", // 允许源 methods: ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"], // 允许方法 allowedHeaders: ["xxx"], // 允许的自定义头 exposedHeaders: ["xxx"], // 要暴露的响应头 }) ); app.get("/xxx", (res, req) => { res.setHeader("xxx", "xxx"); res.send(); }); ``` ## 五、JSONP 解决跨域 JSONP 利用\标签可以跨域加载脚本,且不受严格模式限制的特性。 ### 1. 基本流程 > **第一步:**创建 script 标签,将 src 设置为跨域请求的 url。同时准备一个回调函数,这个函数处理返回来的数据。 > > **第二步:**服务端接受到请求后,将数据封装在回调函数中返回 > > **第三步:**客户端回调函数被调用,数据以参数的形式传入回调函数 ### 2. 例子 **服务端代码** ```javascript let list = [1, 2, 3]; app.get("/table", (req, res) => { const { callback } = req.query; res.send(`${callback}(${JSON.stringify(list)})`); }); ``` **客户端代码** ```javascript function test(data) { console.log(data); } function getTable() { const script = document.createElement("script"); script.onload = () => { script.remove(); }; script.src = "http://xxx.xx.xx:8080/table?callback=test"; document.body.appendChild(script); } ``` ## 六、配置代理解决跨域 ### **1. 自己配置代理服务器** 借助 http-proxy-middleware 配置代理 ```javascript const { createProxyMiddleware } = require("http-proxy-middleware"); app.use( "/api", createProxyMiddleware({ target: "https://www.baidu.com", changeOrigin: true, pathRewrite: { "^/api": "", }, }) ); ``` ### 2. 使用 Nginx 搭建代理服务器 #### 2.1 设置响应头 ```javascript server { listen 80; server_name your_domain.com; location /api/ { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; if ($request_method = 'OPTIONS') { return 204; } proxy_pass http://your_backend_server; } } ``` #### 2.2 反向代理 通过 Nginx 将跨域请求代理到目标服务器,让浏览器认为是同源请求。 ```javascript server { listen 80; server_name frontend.com; location /api/ { proxy_pass http://backend.com; } } ``` ### 3. 脚手架服务器 比如 vue3 里的配置文件 **vite.config.js** 可以配置代理的地址 ```javascript import { defineConfig } from "vite"; // https://vitejs.dev/config/ export default defineConfig(() => { return { server: { host: "127.0.0.1", port: 8081, strictPort: false, open: true, proxy: { "/dev-api": { target: "http://localhost:1112", changeOrigin: true, rewrite: (path) => path.replace(/^\/dev-api/, ""), }, }, }, }; }); ```

相关推荐
敲敲了个代码6 小时前
从硬编码到 Schema 推断:前端表单开发的工程化转型
前端·javascript·vue.js·学习·面试·职场和发展·前端框架
张雨zy7 小时前
Pinia 与 TypeScript 完美搭配:Vue 应用状态管理新选择
vue.js·ubuntu·typescript
dly_blog8 小时前
Vue 响应式陷阱与解决方案(第19节)
前端·javascript·vue.js
消失的旧时光-19438 小时前
401 自动刷新 Token 的完整架构设计(Dio 实战版)
开发语言·前端·javascript
console.log('npc')8 小时前
Table,vue3在父组件调用子组件columns列的方法展示弹窗文件预览效果
前端·javascript·vue.js
用户47949283569158 小时前
React Hooks 的“天条”:为啥绝对不能写在 if 语句里?
前端·react.js
我命由我123459 小时前
SVG - SVG 引入(SVG 概述、SVG 基本使用、SVG 使用 CSS、SVG 使用 JavaScript、SVG 实例实操)
开发语言·前端·javascript·css·学习·ecmascript·学习方法
用户47949283569159 小时前
给客户做私有化部署,我是如何优雅搞定 NPM 依赖管理的?
前端·后端·程序员
C_心欲无痕9 小时前
vue3 - markRaw标记为非响应式对象
前端·javascript·vue.js
qingyun9899 小时前
深度优先遍历:JavaScript递归查找树形数据结构中的节点标签
前端·javascript·数据结构