讲师中心 微信公众号
AI工具推荐 视频效率加速

如何解决跨域?常见解决方案浅析

星婷君_2324

星婷君_2324

发布时间:2023-04-25 19:57:58

|

2717人浏览过

|

来源于掘金社区

转载

如何解决跨域?常见解决方案浅析

跨域是开发中经常会遇到的一个场景,也是面试中经常会讨论的一个问题。掌握常见的跨域解决方案及其背后的原理,不仅可以提高我们的开发效率,还能在面试中表现的更加游刃有余。

因此今天就来和大家从前端的角度来聊聊解决跨域常见的几种方式。

什么是跨域

在讲跨域之前,我们先来看看URL的组成内容:

一个URL的组成,通常包含协议、主机名、端口号、路径、查询参数和锚点几个部分。

这里展示了一个URL的示例:

https://www.example.com:8080/path/resource.html?page=1&sort=desc#header

在上述示例中:
● 协议为HTTPS
● 主机名为www.example.com
● 端口号为8080
● 路径为/path/resource.html
● 查询参数为page=1&sort=desc
● 锚点为header

所谓跨域,指的是请求URL中协议、主机名、端口号中任意一个部分不相同。

以上述URL为例,下面几种写法都算是和它跨域:

http://www.example.com:8080/    // 协议不同
https://www.example.a.com:8080/ // 主机名不同
https://www.example.com:8081/   // 端口号不同

为什么会跨域

其实跨域问题的出现是受限于浏览器的同源策略。

所谓同源策略,其实是浏览器的一种安全机制,用于限制一个网页中的网络请求仅能够访问来自同一源(域名、协议和端口号均相同)的资源,主要目的是防止恶意网站通过脚本窃取其他网站的敏感数据,保障用户的隐私和安全。

当浏览器端的脚本(js文件)访问了其他域的网络资源时,就会出现跨域问题。

如何解决跨域

前文说到,跨域问题的出现是受限于浏览器的同源策略,那么常见的解决跨域问题的方案,其实也是围绕着浏览器展开的:

1.代理服务器

在我们平常的开发中,解决跨域问题最常使用的方案是使用代理服务器。

代理服务器解决跨域问题其实是抓住了同源策略只受限于浏览器访问服务器,对于服务器访问服务器并没有限制的特点,作为中间服务器做了一个请求转发的功能。

具体来说,就是前端工程师编写的网页运行在由webpack等脚手架搭建的代理服务器上,当前端网页在浏览器中发起网络请求时,其实这个请求是发送到代理服务器上的,然后代理服务器会将请求转发给目标服务器,再将目标服务器返回的响应转发给客户端。

代理服务器在此过程中扮演了一个中转的角色,可以对请求和响应进行一些修改、过滤和拦截,以实现一些特定的功能。因为前端网页运行在代理服务器上,所以不存在跨域问题。

那么在线上环境和开发环境下,代理服务器是如何做请求转发的呢?

1.线上环境

在线上环境下,我们一般会采用nginx来做反向代理,从而把前端的请求转发到目标接口上。

nginx是一个轻量级高并发的web服务器,基于事件驱动,而且跨平台,window和Linux都可以进行配置。

它作为代理服务器来解决开发中的跨域问题的主要方法就是监听线上前端网址的运行端口,然后碰到包含特殊标记的请求后就进行请求转发。

2.开发环境

在开发环境下,无论是借助于webpack还是使用vite或其他脚手架搭建的前端项目,解决跨域问题的核心是借助http-proxy-middleware中间件实现的。而http-proxy-middleware中间件的核心又是对http-proxy的进一步封装。

这里先展示一下在项目中使用http-proxy-middleware来实现请求转发功能的示例代码:

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = {
  server: {
    proxy: {
      // 将 /api/* 的请求代理到 http://localhost:3000/*
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        pathRewrite: { '^/api': '/' }
      }
    }
  }
};

接着我们可以自己使用原生node,借助http-proxy库来搭建一个具有请求转发功能的代理服务器Demo,感兴趣的朋友可以自己测试玩玩:

1. 首先需要创建一个空文件夹(全英命名)作为项目文件夹,然后使用npm init -y命令将项目升级为node的项目:

npm init -y

2. 接着在项目根目录下创建一个index.html文件用于发起跨域请求:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>请求转发测试</title>
</head>

<body>
    <h1>请求转发测试</h1>
    <p id="message"></p>
    <script>
        fetch('/api/login')
            .then(response => response.text())
            .then(data => {
                document.getElementById('message').textContent = data;
            });
    </script>
</body>

</html>

3. 接着在项目根目录下新建index.js文件来编写服务端的代码。
index.js文件是实现具有请求转发功能的代理服务器的核心文件。

创意前端视觉设计
创意前端视觉设计

在创建或重塑需要独特视觉方向、应避免通用 AI 生成审美的网站、落地页、仪表盘、UI 组件、海报或应用时使用。

下载
const http = require('http');
const httpProxy = require('http-proxy');
const fs = require('fs');
const path = require('path');

// 创建代理服务器实例
const proxy = httpProxy.createProxyServer({});

// 创建HTTP服务器
const server = http.createServer((req, res) => {
    if (req.url === '/' || req.url.endsWith('.html')) {
        // 读取HTML文件
        const filename = path.join(__dirname, 'index.html');
        fs.readFile(filename, 'utf8', (err, data) => {
            if (err) {
                res.writeHead(500);
                res.end('Error reading HTML file');
            } else {
                res.writeHead(200, { 'Content-Type': 'text/html' });
                res.end(data);
            }
        });
    } else if (req.url.startsWith('/api')) {
        // 重写路径,替换跨域关键词
        req.url = req.url.replace(/^\/api/, '');
        // 将请求转发至目标服务器
        proxy.web(req, res, {
            target: 'http://localhost:3000/',
            changeOrigin: true,
        });    
    }
});

// 监听端口
server.listen(8080, () => {
    console.log('Server started on port 8080');
});

4. 接着编写目标服务器target.js文件的内容,用于测试跨域访问:

const http = require('http');

const server = http.createServer((req, res) => {
    if (req.url.startsWith('/login')) {
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('我是localhost主机3000端口下的方法,恭喜你访问成功!');
    } else {
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('Hello, world!');
    }
});

server.listen(3000, () => {
    console.log('Target server is listening on port:3000');
})

5. 打开终端,输入启动目标服务器的命令:

node ./target.js //项目根目录下执行

6. 再开一个终端启动代理服务器,等待浏览器端发起请求就可以啦:

node ./index.js //项目根目录下执行

7. 最后在浏览器里访问http://localhost:8080, 打开控制台即可查看效果:

可以发现,浏览器network模块的网络请求确实是访问的8080端口的方法,但是我们的服务器默默的做了请求转发的功能,并将请求转发获取到的内容返回到了前端页面上。

其实http-proxy是对node内置库http的进一步封装,网络请求的核心部分还是使用http创建一个服务器对象去访问的。感兴趣的同学可以再读读http-proxy的源码~

除了代理服务器这种绕过浏览器同源策略的解决方式外,从前端的角度解决跨域问题还有如下一些常见的方法:

1.借助JSONP

JSONP的原理是通过动态创建<script>标签</script>,向服务器发送请求并在请求URL中传递一个回调函数名(通常是在本地定义的函数名),服务器在返回的数据中将这个回调函数名和实际数据一起封装成一个JavaScript函数的调用,返回给客户端,客户端利用该回调函数对数据进行处理。

JSONP之所以能够跨域请求数据,是因为浏览器对于<script>标签的请求不会受到同源策略的限制。</script>

需要注意的是,使用JSONP技术的前提是服务器需要支持JSONP的方式,即在返回的数据中包含回调函数名和实际数据的封装,否则客户端无法处理返回的数据。

此外,JSONP只支持GET请求,不支持POST等其他HTTP请求方式,因为<script>标签只支持GET请求。</script>

因此JSONP这种方式在我们的开发中使用的场景不多。

2.使用CORS

CORS全称为Cross-Origin Resource Sharing,它通过HTTP头部信息告诉浏览器哪些跨域请求是被允许的,从而实现安全的跨域访问。

CORS解决跨域需要浏览器端和服务器端的配合。原理是在服务器端设置HTTP头部信息,告诉浏览器允许哪些源(域名、协议、端口)访问服务器上的资源,如果请求的源不在允许的列表中,则浏览器将拒绝访
问。

服务器可以通过设置Access-Control-Allow-Origin、Access-Control-Allow-Headers、Access-Control-Allow-Methods等HTTP头部信息来控制跨域访问权限。

具体地,当浏览器发起跨域请求时,会先发送一个OPTIONS请求(预检请求),询问服务器是否允许该跨域请求。

服务器接收到该请求后,根据请求中的HTTP头部信息判断是否允许该请求。

如果允许,则返回相应的HTTP头部信息告知浏览器可以继续发送真正的跨域请求。如果不允许,则返回一个错误状态码,告诉浏览器该请求被拒绝。

预检请求时,请求头常见参数有:

请求头 值
Origin 表示请求的源地址,即发起跨域请求的域名
Access-Control-Request-Method 表示实际请求采用的HTTP方法
Access-Control-Request-Headers 表示实际请求中所携带的额外请求头信息,比如自定义请求头等

预检请求时,响应头常见参数有:

响应头 值
Access-Control-Allow-Origin *、origin...
Access-Control-Allow-Headers POST, GET, PUT, DELETE, OPTIONS
Access-Control-Allow-Methods Content-Type, Authorization..
Access-Control-Allow-Credentials true
Access-Control-Max-Age 86400

需要注意的是,使用CORS的前提是服务器需要设置相关的HTTP头部信息,且浏览器支持CORS。此外,CORS只支持现代浏览器,对于一些老旧的浏览器可能不支持CORS。

3.其他方案

比如WebSocket、postMessage等等

总结

近年来,随着前后端技术的飞速发展,前后端独立开发逐渐成为主流的开发模式。前后端程序员只需约定好接口,然后独自进行相应模块的开发,最后进行接口联调即可。在接口联调过程中,开发环境下的跨域就是一个需要解决的问题。

除此之外,当前后端项目打包上云后,前端页面通过线上地址访问后台接口时,线上环境下的跨域也是一个需要解决的问题。

本文讲述了几种常见的跨域解决方案,这些方案各有优缺点,大家可以根据实际情况选择适合的方案来解决对应的跨域问题~

推荐教程:nginx教程

热门AI工具

更多
PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

码上飞
码上飞 Hot

一款基于自然语言的AI应用开发平台,可根据用户描述自动生成应用程序,帮助个人和团队快速完成应用原型与开发。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

相关专题

更多
Docker Desktop怎么设置端口映射
Docker Desktop怎么设置端口映射

本专题聚焦Docker Desktop容器端口映射与访问配置,整理从创建容器、设置端口绑定到验证本地服务访问的操作流程。针对端口被占用、映射配置错误、容器服务无法访问等情况,也提供相应的检查方向,方便用户完成端口配置。

0

2026.11.03

Docker Desktop镜像构建教程
Docker Desktop镜像构建教程

想使用Docker Desktop将本地项目构建成Docker镜像?本专题围绕镜像构建的实际操作展开,介绍Dockerfile编写、构建命令使用、镜像标签设置和构建日志查看等内容,同时整理镜像无法生成、依赖安装失败及构建缓存异常等问题的排查思路。

0

2026.11.03

Docker Desktop容器创建指南
Docker Desktop容器创建指南

本专题聚焦Docker Desktop容器创建与运行配置,介绍通过本地镜像或远程镜像创建容器的方法,以及容器启动、终端访问、日志查看和基础管理等操作。针对端口冲突、参数配置不当、容器无法启动等情况,也整理了相应的排查方向。

0

2026.11.03

Tailwind CSS 如何制作导航栏和卡片
Tailwind CSS 如何制作导航栏和卡片

用 Tailwind CSS 制作导航栏和卡片,可先搭建语义化结构,再组合 Flex、Grid、间距、圆角与阴影类。这里整理横向导航、移动端菜单、卡片网格及悬停效果的相关文章,帮助你把常见页面组件做得清晰且适配不同屏幕。

0

2026.11.03

Tailwind CSS 响应式布局怎么写
Tailwind CSS 响应式布局怎么写

Tailwind CSS 响应式布局通常从移动端样式写起,再用 sm、md、lg 等前缀调整不同屏幕宽度下的网格、间距和导航。本专题整理断点配置、Grid 与 Flex 自适应布局及常见溢出问题,帮助你逐步完成多设备适配。

0

2026.11.03

Tailwind CSS 常用类名怎么记
Tailwind CSS 常用类名怎么记

Tailwind CSS 类名很多,先按布局、间距、文字、颜色和状态分组记忆,再通过官方文档检索具体写法。本专题结合类名排序、动态拼接失效、自定义实用类等问题,帮助你建立常用类名的速查方法。

0

2026.11.03

码上飞入口地址合集
码上飞入口地址合集

本专题汇总了码上飞(CodeFlying)的官方入口地址合集,涵盖官网主站及网页版在线使用入口,支持注册登录后直接在线体验零代码AI应用生成。同时整理了APP端下载渠道与小程序入口,助你快速访问平台,通过自然语言描述需求即可生成应用、小程序或网站。

0

2026.11.03

Uvicorn 报错与问题解决教程
Uvicorn 报错与问题解决教程

本专题汇总了Uvicorn服务器常见问题与报错解决的教程合集,涵盖启动失败、端口占用、模块导入错误、事件循环冲突及热重载失效等典型故障的排查思路。同时整理了多进程与Worker配置、SSL/HTTPS证书报错、跨域与代理配置等实战解决方案,助你快速定位并解决Uvicorn运行中的各类问题。

20

2026.11.02

Uvicorn使用教程
Uvicorn使用教程

本专题汇总了Uvicorn使用教程与启动运行指南,涵盖其作为Python ASGI服务器的定位与特点,以及命令行启动(uvicorn main:app --reload)、参数配置(host/port/workers)、程序内嵌运行与Gunicorn结合部署等核心用法。同时整理了热重载调试、日志配置与生产环境部署优化等技巧,助你快速掌握Uvicorn的运行与配置。

40

2026.11.02

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn