CORS解决前端跨域案例学习

news2024/12/24 21:32:08

跨域的概念不再解释,直接演示下出现跨域的情况:

前端代码(index.html):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CORS Example</title>
</head>
<body>
    <h1>CORS Example</h1>
    <button id="fetchData">Fetch Data</button>
    <p id="result"></p>

    <script>
        document.getElementById('fetchData').addEventListener('click', () => {
            fetch('http://localhost:4000/data')
                .then(response => response.json())
                .then(data => {
                    document.getElementById('result').innerText = JSON.stringify(data);
                })
                .catch(error => {
                    console.error('Error:', error);
                });
        });
    </script>
</body>
</html>

点击Fetch Data按钮,向http://localhost:4000/data请求数据

后端代码(server.js):

const express = require("express");
const app = express();
const port = 4000;

app.get("/data", (req, res) => {
  res.json({ message: "This is some data from the server." });
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

首先我们直接启动服务器:

node server.js

打开浏览器直接输入http://localhost:4000/data 回车,可以返回数据,而且没有任何错误
在这里插入图片描述

此时,我们通过vs code 中的插件 live server打开index.html,这种方式的含义是,本地启动一个开发服务器,域名为http://127.0.0.1:5501,当前位置为http://127.0.0.1:5501/index.html
在这里插入图片描述

Access to fetch at ‘http://localhost:4000/data’ from origin ‘http://127.0.0.1:5501’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

点击按钮时,报错,意思是说,我们当前所在域名为http://127.0.0.1:5501,去请求了一个非同源的资源http://localhost:4000/data,因为是非同源的,出现了跨域情况,这时候被浏览器拦截了,可以发现响应的状态码是200,ok 的
在这里插入图片描述

解决:

通过手动设置Access-Control-Allow-Origin和其他CORS相关的头部来解决跨域问题。

后端代码(server.js)

const express = require('express');
const app = express();
const port = 4000;

app.get('/data', (req, res) => {
    // 设置CORS头部
    res.setHeader('Access-Control-Allow-Origin', '*'); // 允许所有来源(跨域)
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); // 允许的HTTP方法
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 允许的头部
    res.json({ message: 'This is some data from the server.' });
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

我们针对要访问的资源路径 http://localhost:4000/data,配置该资源对于跨域请求的限制。

  1. Access-Control-Allow-Origin: 表示的是可以被来自哪些域的请求访问到。
    该头部指定了允许跨域访问的域。可以设置为特定的域名(比如本例中http://localhost:5501),或使用*表示允许任何域名访问。
  2. Access-Control-Allow-Methods:该头部指定了允许的HTTP方法。例如,可以允许GET、POST、PUT、DELETE等方法。
  3. Access-Control-Allow-Headers:该头部指定了前端在请求中允许使用的自定义头部字段。例如,如果请求中包含Content-Type或Authorization头部,则需要在这里指定。

之后,我们就可以访问到该资源
在这里插入图片描述

处理预检请求(OPTIONS)

某些请求(如带有自定义头部的POST请求)会触发浏览器的“预检请求”(OPTIONS方法)。预检请求的作用是让浏览器先确认服务器是否允许跨域访问

简单请求:

请求方法为:GET、POST、HEAD,请求头 Content-Type 为:text/plain、multipart/form-data、application/x-www-form-urlencoded 的就属于 “简单请求” 不会触发 CORS 预检请求。

非简单请求:

使用的HTTP方法超出了GET、POST、HEAD,如PUT、DELETE等,请求头的 Content-Type 为 application/json 就会触发 CORS 预检请求,这里也会称为 “非简单请求”。

特点:
在实际请求发送之前,浏览器会自动发起一个OPTIONS请求,这就是所谓的预检请求。预检请求用来向服务器询问实际请求是否被允许。

服务器必须正确响应预检请求:服务器需要在预检请求中返回正确的CORS头部,以允许实际请求的发送。

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Non-Simple Request Example</title>
</head>
<body>
    <h1>Non-Simple Request Example</h1>
    <button id="sendRequest">Send Non-Simple Request</button>
    <p id="response"></p>

    <script>
        document.getElementById('sendRequest').addEventListener('click', () => {
            fetch('http://localhost:4000/data', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Bearer some-token' // 自定义头部
                },
                body: JSON.stringify({ key: 'value' }) // 请求体
            })
            .then(response => response.json())
            .then(data => {
                document.getElementById('response').innerText = JSON.stringify(data);
            })
            .catch(error => {
                console.error('Error:', error);
            });
        });
    </script>
</body>
</html>

后端:

const express = require('express');
const app = express();
const port = 4000;

app.use(express.json()); // 解析JSON请求体

// 处理预检请求,设置CORS头部并返回204 No Content状态码,表明服务器允许实际请求的发送。
app.options('/data', (req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'POST');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    res.sendStatus(204); // 204 No Content
});
 
// 处理实际的POST请求,并返回JSON数据
app.post('/data', (req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.json({ message: 'Data received successfully', receivedData: req.body });
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

在点击按钮之后,可以发现发送了两次网络请求,第一次为预检请求,第二次为post请求
在这里插入图片描述
options请求:
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

comfyUI工作流也能变现了,“SD变现宝”把工作流转为小程序,重塑内容创作者的商业之路

前言 在数字化浪潮的推动下&#xff0c;内容创作行业正经历着前所未有的变革。如何在这个充满竞争与机遇的时代中脱颖而出&#xff0c;成为每个创作者必须面对的挑战。 SD变现宝&#xff0c;作为ComfyUI的最新插件&#xff0c;凭借其独特的功能与优势&#xff0c;为创作者们开…

赋能未来制造:三品图文档管理软件在大连船推图文档管理中的深度应用与成效

在信息化浪潮席卷全球的今天&#xff0c;企业的研发管理能力已经成为衡量其核心竞争力的重要标尺。三品软件与大连船用推进器有限公司携手合作&#xff0c;成功实施了EDM图文档协同管理系统项目&#xff0c;为企业在激烈的市场竞争中提供强有力的支持&#xff0c;确保其始终处于…

RCE绕过练习

一.了解eval与assert eval与assert区别_eval assert-CSDN博客https://blog.csdn.net/qq_53568983/article/details/129782507 看了php官方文档,assert中提到的许多名词不明白,转而搜索文章,这篇是解释的是最直白的 其中提到eval不是一个函数,是语言构造器,不能被可变函数调用…

Git代码管理规范

1. 简介 git 分支分为集成分支、功能分支和修复分支&#xff0c;分别命名为 develop、feature 和 hotfix&#xff0c;均为单数。不可使用 features、future、hotfixes、hotfixs 等错误名称。 master&#xff08;主分支&#xff0c;永远是可用的稳定版本&#xff0c;不能直接在…

数据中台运营与实战案例集锦(125页PPT)

方案简介&#xff1a; 本篇通过理论讲解与实战案例相结合的方式&#xff0c;深入剖析了数据中台的概念、架构、关键技术、实施路径以及运营策略。内容覆盖从数据中台规划到落地的全过程&#xff0c;包括数据治理、数据资产管理、数据服务化、数据分析与挖掘、以及如何通过数据…

PythonStudio 控件使用常用方式(二十六)TProgressBar

PythonStudio是一个极强的开发Python的IDE工具&#xff0c;官网地址是&#xff1a;https://glsite.com/ &#xff0c;在官网可以下载最新版的PythonStudio&#xff0c;同时&#xff0c;在使用PythonStudio时&#xff0c;它也能及时为用户升到最新版本。它使用的是Delphi的控件&…

MySQL:复杂查询(一)——聚合函数分组查询联合查询01

目录 1、聚合查询 1.1 聚合函数 1.1.1 COUNT() 1.1.2 SUM() 1.1.3 AVG() 1.1.4 MAX()&#xff0c;MIN() 1.2 分组查询 1.2.1 GROUP BY子句 1.2.1.1 round() 1.2.2 HAVING 1.2.3 示例 2、联合查询&#xff08;表连接查询&#xff09; 2.1 内连接 2.1.1 ①取相关表笛…

机器学习——全连接(MLP多层感知机)的理解

全连接即是矩阵乘&#xff0c;因此在transformer中获取QKV理论上是输入与QKV权重矩阵相乘&#xff0c;但实际操作则是使用全连接即nn.Linear()&#xff0c;注意这里的输入和输出都是二维的[batch,d_model]&#xff0c;即每个样本是一维的。

【Echarts】custom自定义图表实现甘特图

效果图 主要注意点&#xff1a; 1、右上角图例visualMap实现 2、visualMap增加formatter 3、series使用custom自定义图表&#xff0c;encode解析四维数组。核心是renderItem方法&#xff0c;必填项&#xff0c;且需要注意要全部定义在options里面&#xff01;&#xff01;&…

程序员如何平衡日常编码工作与提升式学习?

程序员的两难&#xff1a;如何平衡日常编码与持续学习 在科技日新月异、更新迭代迅速的编程世界中&#xff0c;程序员面临的一个重要挑战是如何在繁忙的日常编码工作和持续的专业提升之间找到平衡。是否应当在工作时间全身心投入到项目推进中&#xff0c;还是应该抽出时间学习…

第38篇 冒泡排序<二>

Q&#xff1a;如何设计C语言程序对数组进行降序排列&#xff1f; A&#xff1a;基本原理&#xff1a;通过不断的比较和交换数组中的数据元素&#xff0c;最终使得最大的数据“冒泡”排到到数组最末&#xff0c;并逐步缩小待排序的范围直到所有数据都排列正确位置。首先定义简单…

行业大模型:信用评分大模型、生产优化大模型、库存管理大模型、物流行业大模型、零售行业大模型

金融行业大模型&#xff1a;信用评分大模型 信用评分模型在金融行业中扮演着至关重要的角色&#xff0c;它通过对个人或企业的信用状况进行评估&#xff0c;帮助金融机构有效控制风险&#xff0c;提高业务效率。以下是信用评分模型的特点及案例介绍&#xff1a; 信用评分模型…

git放弃本地add/commit

git放弃本地add/commit 还未添加add的情况已经执行git add缓存了的&#xff1a;可以用命令 还未添加add的情况 # 放弃某个文件git checkout <filename># 放弃所有文件git checkout .已经执行git add缓存了的&#xff1a;可以用命令 git reset HEAD filepathname &#x…

【开端】如何高效记录并整理编程学习笔记

如何高效记录并整理编程学习笔记&#xff1f; 在编程学习的海洋中&#xff0c;高效的笔记记录和整理方法就像一张珍贵的航海图&#xff0c;能够帮助我们在浩瀚的知识中找到方向。如何建立一个既能快速记录又易于回顾的笔记系统&#xff1f;如何在繁忙的学习中保持笔记的条理性…

巴黎奥运会中国奖牌数据分析

目录 一、每个比赛日奖牌变化数据分析 二、奖牌项目占比数据分析 2.1金牌中项目占比分析 2.2 银牌中项目占比分析 2.3 铜牌中项目占比分析 2.4 奖牌总数中项目占比分析 在巴黎奥运会上&#xff0c;中国队的表现可谓亮眼&#xff0c;各项比赛日的奖牌总数和不同项目的奖牌…

【软件测试】功能测试理论基础

目录 项目的测试流程&#x1f3f4; 需求评审 评审形式 测试人员在需求评审中职责 测试计划与方案 测试计划 问题 测试方案&#x1f3f4; 测试计划与方案的对比 功能测试设计&#x1f3f4; 测试设计的步骤 项目的测试流程&#x1f3f4; 作用&#xff1a; 有序有效开展…

js 深拷贝、浅拷贝深度解析

赋值操作&#xff1a; let obj{a:1,b:[1,2,3],c:{m:2}}let newObjobjnewObj.a2newObj.b.push(4)newObj.c.m3console.log(obj,newObj); 将一个对象赋值给一个变量&#xff0c;其实就是将这个对象在栈内存中的引用地址复制给了这个变量&#xff0c;这两个对象指向堆内存中的同一个…

基于SpringBoot+Vue的产业园区智慧公寓管理系统(带1w+文档)

基于SpringBootVue的产业园区智慧公寓管理系统(带1w文档) 基于SpringBootVue的产业园区智慧公寓管理系统(带1w文档) 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包…

Multisim 用LM358 运放模拟线性稳压器 - 运放输出饱和 - 前馈电容

就是拿运放搭一个可调的LDO 稳压器&#xff0c;类似下面这个功能框图里的感觉。本来应该非常简单&#xff0c;没什么好说的&#xff0c;没想到遇到了两个问题。 原理 - 理想运放 我用PNP 三极管Q2 作为输出&#xff0c;运放输出电压升高时&#xff0c;流过PNP 三极管BE 的电流变…

【proteus经典实战】报警器与旋转灯

一、简介 报警器与旋转灯项目是一个典型的嵌入式系统应用&#xff0c;它结合了声音报警和视觉指示功能&#xff0c;广泛应用于安全监控、紧急疏散、交通信号和娱乐设备等多种场景。基于51单片机提供一种集成的声音和视觉报警解决方案&#xff0c;通过声音和灯光的结合&#xff…