什么是跨域?——详解跨域问题及其解决方案

目录

  1. 引言
  2. 什么是跨域
  3. 同源策略
  4. 跨域的产生原因
  5. 跨域的常见解决方案
    • JSONP
    • CORS
    • 代理服务器
    • nginx反向代理
    • 后端设置允许跨域
  6. CORS的详细实现
    • 浏览器中的CORS支持
    • 服务器端的CORS配置
  7. 常见的跨域场景和解决方案
    • 跨域请求API
    • 跨域加载资源
  8. 跨域的安全性考虑
  9. 跨域调试技巧
  10. 总结

引言

在现代Web开发中,前后端分离的架构设计已成为常态。然而,当前端向不同域名的后端服务器请求数据时,常会遇到跨域问题。理解并解决跨域问题,不仅能保证数据的正常交互,还能提升用户体验和应用的安全性。

什么是跨域

跨域(Cross-Origin)指的是浏览器阻止前端网页从一个域名(Origin)向另一个域名的服务器发送请求。具体来说,一个页面的协议、域名、端口三者任意一个与请求的目标地址不同,就被视为跨域请求。

举例说明:

  • http://example.com 请求 http://api.example.com 会跨域,因为域名不同。
  • http://example.com 请求 https://example.com 会跨域,因为协议不同。
  • http://example.com:8080 请求 http://example.com:9090 会跨域,因为端口不同。

同源策略

同源策略(Same-Origin Policy)是浏览器的一个重要安全机制,防止恶意网站通过跨域方式窃取敏感数据。该策略限制了从一个源加载的文档或脚本如何与另一个源的资源进行交互。

同源策略的定义:如果两个URL的协议、域名和端口都相同,则这两个URL具有相同的源。

同源策略的影响

同源策略影响以下几类数据访问:

  • Cookie、LocalStorage 和 IndexedDB
  • DOM 和 JavaScript 对象
  • AJAX 请求

跨域的产生原因

跨域问题主要是由于浏览器的同源策略所致。随着前后端分离架构的流行,前端开发常常需要向不同域名的后端服务器请求数据,从而产生跨域问题。

跨域的常见解决方案

JSONP

JSONP(JSON with Padding)是一种传统的跨域解决方案,通过动态创建<script>标签来实现跨域请求,因为<script>标签不受同源策略的限制。

实现原理

JSONP通过在URL中传递回调函数的名称,后端返回对应的JavaScript代码,前端执行该代码,从而实现数据的获取。

示例代码

前端代码:

<!DOCTYPE html>
<html>
<head><title>JSONP Demo</title>
</head>
<body><script>function handleResponse(data) {console.log('Received data:', data);}const script = document.createElement('script');script.src = 'http://example.com/api?callback=handleResponse';document.body.appendChild(script);</script>
</body>
</html>

后端代码(假设为Node.js):

const http = require('http');http.createServer((req, res) => {const callbackName = req.url.match(/callback=([^&]+)/)[1];const responseData = { message: 'Hello, world!' };res.writeHead(200, { 'Content-Type': 'application/javascript' });res.end(`${callbackName}(${JSON.stringify(responseData)})`);
}).listen(80, 'example.com');

CORS

CORS(Cross-Origin Resource Sharing)是现代解决跨域问题的标准方法,通过HTTP头来告诉浏览器,允许哪些跨域请求。

实现原理

CORS通过设置HTTP响应头Access-Control-Allow-Origin,告诉浏览器哪些域名可以访问资源。

示例代码

前端代码:

fetch('http://api.example.com/data', {method: 'GET',headers: {'Content-Type': 'application/json'}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

后端代码(假设为Node.js和Express):

const express = require('express');
const app = express();app.use((req, res, next) => {res.header('Access-Control-Allow-Origin', '*');res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');next();
});app.get('/data', (req, res) => {res.json({ message: 'Hello, world!' });
});app.listen(80, 'example.com');

代理服务器

代理服务器可以绕过浏览器的同源策略,将跨域请求转发到目标服务器。

示例代码

前端代码:

fetch('/api/data', {method: 'GET',headers: {'Content-Type': 'application/json'}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

后端代码(假设为Node.js和Express):

const express = require('express');
const request = require('request');
const app = express();app.use('/api', (req, res) => {const url = 'http://api.example.com' + req.url;req.pipe(request(url)).pipe(res);
});app.listen(3000, () => {console.log('Proxy server running on port 3000');
});

nginx反向代理

通过配置nginx反向代理,也可以实现跨域请求。

配置示例
server {listen 80;location /api/ {proxy_pass http://api.example.com/;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}
}

后端设置允许跨域

通过在后端设置CORS响应头,允许特定域名访问资源。

示例代码

后端代码(假设为Spring Boot):

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Beanpublic WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/api/**").allowedOrigins("http://example.com").allowedMethods("GET", "POST", "PUT", "DELETE").allowedHeaders("*").allowCredentials(true);}};}
}

CORS的详细实现

浏览器中的CORS支持

CORS在浏览器中的实现是通过在请求和响应中添加相应的HTTP头部字段来完成的。常见的CORS相关头部字段包括:

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

服务器端的CORS配置

不同的后端框架和服务器有不同的CORS配置方法。以下是一些常见的配置示例。

Node.js和Express
const express = require('express');
const cors = require('cors');
const app = express();app.use(cors());app.get('/data', (req, res) => {res.json({ message: 'Hello, world!' });
});app.listen(80, () => {console.log('Server running on port 80');
});
Spring Boot
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Beanpublic WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/api/**").allowedOrigins("http://example.com").allowedMethods("GET", "POST", "PUT", "DELETE").allowedHeaders("*").allowCredentials(true);}};}
}

常见的跨域场景和解决方案

跨域请求API

当前端请求不同域名的API时,需要解决跨域问题。可以通过CORS、JSONP或代理服务器等方法来实现。

跨域加载资源

跨域加载资源(如图片、脚本、样式表等)时,同样需要解决跨域问题。通常通过CORS头部来允许跨域加载。

跨域的安全性考虑

跨域请求涉及安全性问题,特别是当允许外部网站访问敏感数据时。以下是一些安全性考虑:

  • 仅允许可信任的域名进行跨域请求。
  • 使用Access-Control-Allow-Credentials头部来限制跨域请求的凭证传递。
  • 避免通过JSONP传递敏感数据。

跨域调试技巧

在调试跨域问题时,可以使用以下技巧:

  • 使用浏览器的开发者工具查看请求和响应头部。
  • 使用代理服务器或nginx进行本地调试。
  • 查看后端服务器的日志,确认CORS配置是否正确。

总结

跨域问题是Web开发中常见的问题,理解跨域的原理及其解决方案对于前后端分离开发尤为重要。本文详细介绍了跨域的概念、同源策略、跨域的产生原因及常见的解决方案,包括JSONP、CORS、代理服务器、nginx反向代理等。通过合理配置和编写代码,我们可以有效地解决跨域问题,确保前后端数据的正常交互。

希望本文能帮助您深入理解跨域问题及其解决方案。如果您有任何问题或建议,欢迎在评论区留言讨论。

Happy Coding!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/40583.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python+playwright 学习-90 and_ 和 or_ 定位

前言 playwright 从v1.34 版本以后支持and_ 和 or_ 定位 XPath 中的and和or xpath 语法中我们常用的有text()、contains() 、ends_with()、starts_with() //*[text()="文本"] //*[contains(@id, "xx")] //

LLM - 循环神经网络(RNN)

1. RNN的关键点&#xff1a;即在处理序列数据时会有顺序的记忆。比如&#xff0c;RNN在处理一个字符串时&#xff0c;在对字母表顺序有记忆的前提下&#xff0c;处理这个字符串会更容易。就像人一样&#xff0c;读取下面第一个字符串会更容易&#xff0c;因为人对字母出现的顺序…

idea MarketPlace插件找不到

一、背景 好久没用idea了&#xff0c;打开项目后没有lombok&#xff0c;安装lombok插件时发现idea MarketPlace插件市场找不到&#xff0c;需要重新配置代理源&#xff0c;在外网访问时通过代理服务进行连接 二、操作 ### File-->setting 快捷键 Ctrl Alt S 远端源地…

动手学深度学习(Pytorch版)代码实践 -循环神经网络-53语言模型和数据集

53语言模型和数据集 1.自然语言统计 引入库和读取数据&#xff1a; import random import torch from d2l import torch as d2l import liliPytorch as lp import numpy as np import matplotlib.pyplot as plttokens lp.tokenize(lp.read_time_machine())一元语法&#xf…

类和对象深入理解

目录 static成员概念静态成员变量面试题补充代码1代码2代码3如何访问private中的成员变量 静态成员函数静态成员函数没有this指针 特性 友元友元函数友元类 内部类特性1特性2 匿名对象拷贝对象时的一些编译器优化 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接…

Linux-DNS

DNS域名解析服务 1.DNS介绍 DNS 是域名系统 (Domain Name System) 的缩写&#xff0c;是因特网的一项核心服务&#xff0c;它作为可以将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便的访问互联网&#xff0c;而不用去记住能够被机器直接读取的IP数串。…

大气热力学(2)——热力学基础

本篇文章源自我在 2021 年暑假自学大气物理相关知识时手写的笔记&#xff0c;现转化为电子版本以作存档。相较于手写笔记&#xff0c;电子版的部分内容有补充和修改。笔记内容大部分为公式的推导过程。 文章目录 2.0 本文所用符号一览2.1 准静态过程2.2 热量和热容量2.2.1 热量…

Java对象

面向对象和面向过程的区别 两者的主要区别在于解决问题的方式不同 面向过程把解决问题的过程拆成一个个方法&#xff0c;通过一个个方法的执行解决问题。 面向对象会先抽象出对象&#xff0c;然后用对象执行方法的方式解决问题。 另外&#xff0c;面向对象开发的程序一般更易维…

乞丐传武功

题目 你施舍给了路边的乞丐两个馒头&#xff0c;谁料这个乞丐其实是隐士高人。为了回报你的善心&#xff0c;只见他缓缓从怀中掏出了数本武功秘籍&#xff0c;让你从中挑选一本。你珍重地接过这些秘籍&#xff0c;目光扫过每本封面&#xff0c;降龙十八掌、神照经、易筋经、凌…

[FreeRTOS 基础知识] 互斥量 概念

文章目录 基础知识互斥量互斥量与信号量区别优先级反转优先级继承小结 基础知识 [FreeRTOS 基础知识] 信号量 概念 互斥量 互斥量&#xff08;Mutex&#xff0c;全称&#xff1a;Mutual Exclusion&#xff09;&#xff0c;在计算机科学中&#xff0c;是一种用于防止多个进程同…

科研绘图系列:R语言实验结果组图(linechart + barplot)

介绍 实验结果的多样性意味着每个结果都可能揭示研究的不同方面或角度。在科学研究和数据分析中,通常我们会收集一系列数据点,每个数据点都对应着实验的一个特定变量或条件。为了全面理解这些数据,我们可能会采用多种可视化技术来展示它们。 将多个结果分别可视化,可以让…

亲子时光里的打脸高手,贾乃亮与甜馨的父爱如山

贾乃亮这波操作&#xff0c;简直是“实力打脸”界的MVP啊&#xff01; 7月5号&#xff0c;他一甩手&#xff0c;甩出张合照&#xff0c; 瞬间让多少猜测纷飞的小伙伴直呼&#xff1a;“脸疼不&#xff1f;”带着咱家小甜心甜馨&#xff0c; 回了哈尔滨老家&#xff0c;这趟亲…

Nginx(http配置、https配置)访问Spring Boot 项目

前文 记录一下在linux服务器下配置nginx中nginx.conf文件代理访问springboot项目 1. spring boot.yml配置 其他mysql,redis,mybatis等之类的配置就不一一列出了 # 自定义配置 为了等下验证读取的配置文件环境 appName: productserver:port: 8083 # 应用服务 WEB 访问端口s…

SQL窗口函数详解

详细说明在sql中窗口函数是什么&#xff0c;为什么需要窗口函数&#xff0c;有普通的聚合函数了那窗口函数的意义在哪&#xff0c;窗口函数的执行逻辑是什么&#xff0c;over中的字句是如何使用和理解的&#xff08;是不是句句戳到你的痛点&#xff0c;哼哼&#xff5e;&#x…

C语言编译和编译预处理

编译预处理 • 编译是指把高级语言编写的源程序翻译成计算机可识别的二进制程序&#xff08;目标程序&#xff09;的过程&#xff0c;它由编译程序完成。 • 编译预处理是指在编译之前所作的处理工作&#xff0c;它由编译预处理程序完成 在对一个源程序进行编译时&#xff0c;…

全国青少年软件编程等级考试-四级-奇偶之和(真题)

题目&#xff1a;奇偶之和 1.准备工作 (1)保留舞台中的小猫角色&#xff1b; 2.功能实现 (1)分别计算1&#xff5e;100中&#xff0c;奇数之和&#xff0c;偶数之和&#xff1b; (2)说出奇数之和&#xff0c;偶数之和。 讲解&#xff1a; 1、如何判断奇偶数 奇数是指除以2有…

C++deque容器

文章目录 deque容器概念deque操作deque对象的带参数构造deque头部和末尾的添加移除操作deque的数据存取deque与迭代器deque赋值deque插入deque删除 deque容器概念 deque是双端数组&#xff0c;而vector是单端的。 deque头部和尾部添加或移除元素都非常快速, 但是在中部安插元…

在x86/amd64的机器上使用Docker运行arm64v8/ubuntu并安装ROS1

一、准备工作 主要是因为国内网络的问题&#xff0c;可能导致镜像拉取失败&#xff0c;解决办法参考&#xff1a;镜像加速 二、安装运行过程 2.1拉取镜像&#xff1a; sudo docker pull arm64v8/ubuntu:20.04这个是ubuntu的拉取指令&#xff0c;其他的也是类似。 2.2 运行…

【DevOps】运维过程中经常遇到的Http错误码问题分析(一)

一、解决HTTP 408错误&#xff1a;上传3M文件时请求超时的问题 在开发Web应用程序时&#xff0c;遇到HTTP 408状态码&#xff08;请求超时&#xff09;是常见的问题。特别是在上传大文件时&#xff0c;这种情况更容易发生。本文将探讨在上传一个3M文件时&#xff0c;Web服务器…

LeetCode题练习与总结:排序链表--148

一、题目描述 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例 3&am…