Springboot拦截器中跨域失效的问题、同一个接口传入参数不同,一个成功,一个有跨域问题、拦截器和@CrossOrigin和@Controller

Springboot拦截器中跨域失效的问题

一、概述

1、具体场景

起因:

  • 同一个接口,传入不同参数进行值的修改时,一个成功,另一个竟然失败,而且是跨域问题
  • 拦截器内的request参数调用getHeader方法时,获取不到前端设置的请求头,且浏览器显示有,但是后端输出后只有对于的key,而且key变成了access-control-request-headers的value

同一个接口不同参数错误展示:
在这里插入图片描述


前端代码展示:

在这里插入图片描述


浏览器请求头显示:
在这里插入图片描述


后端获取request的header参数显示:

全是null

在这里插入图片描述

输出headers:

{sec-fetch-mode=cors, referer=http://localhost:8080/, sec-fetch-site=cross-site, accept-language=zh-CN,zh;q=0.9, origin=http://localhost:8080, access-control-request-method=POST, accept=*/*, host=127.0.0.1:8099, access-control-request-headers=content-type,headeruserid,headerusertoken, connection=keep-alive, accept-encoding=gzip, deflate, br, user-agent=Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36, sec-fetch-dest=empty}

变成了这样:access-control-request-headers=content-type,headeruserid,headerusertoken,

2、背景

前端:

  1. 是个uniapp项目,只会调,不会写,未设置跨域

后端:

  1. spring boot项目
  2. 后端使用了@CrossOrigin(origins = "*"),进行了简单的跨域设置
  3. 后端使用了拦截器进行拦截认证

3、尝试改bug

发现前端的参数key,浏览器的参数key和后端的参数key大小写不一致:

  • 修改了多次,且尝试了多次,无效果
String userId = request.getHeader("headerUserId");
String userId2 = request.getHeader("HeaderUserId");
String userId3 = request.getHeader("Headeruserid");

在这里插入图片描述

尝试前端添加跨域:

  • 统一设置跨域请求头,不会,只会小改
  • 前端添加:Access-Control-Allow-Origin: *,无效,后面认真看才发现这是响应头,不是请求头,sha呗了

尝试后端的拦截器内添加@CrossOrigin(origins = “*”)、具体拦截方法内给响应参数添加响应头:

  • 无效

重启前端项目、清除浏览器缓存、清除idea缓存、rebuild项目、重新运行:

  • 无效

二、解决办法

试了很多方法,慢慢的就定位了问题:

  • 前端设置的请求头,浏览器可以接收,而且具体显示,那就不是前端的问题
  • 后端试了很多次,拦截器获取的request header 的key和value还是null
  • 如果取消拦截器,正常可以获取
  • 那么可能是拦截器的问题,我的@CrossOrigin(origins = "*")加在我的接口上,但是拦截器先执行,如果没用通过那么直接返回,根本到不了我的接口,也就到不了我接口上的@CrossOrigin(origins = "*"),那就没用跨域了
  • 但是我尝试再拦截器内的方法中手动给response响应添加跨域的代码,如下,但是还是无效
// 支持跨域
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods",
"GET,POST,PUT,DELETE,OPTIONS");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Token");
response.setHeader("Access-Control-Allow-Credentials", "true");

后面查询跨域的请求流程:

跨域请求的流程通常分为两个阶段:预检请求(Preflight Request)和实际请求。以下是跨域请求的一般流程:

  1. 预检请求阶段

    • 当浏览器检测到跨域请求时(例如请求方法不是简单请求方法、请求包含自定义的请求头等),会首先发送一个预检请求(OPTIONS请求)给服务器。
    • 预检请求的目的是询问服务器是否允许实际请求中包含特定的自定义请求头字段和请求方法。
    • 预检请求会包含一些特定的请求头,如Access-Control-Request-MethodAccess-Control-Request-Headers,用来询问服务器的允许范围。
    • 服务器收到预检请求后,根据预检请求中的信息判断是否允许实际请求,然后发送适当的CORS响应头给浏览器。
  2. 实际请求阶段

    • 如果预检请求得到了服务器的允许(即服务器返回了合适的CORS响应头),浏览器将发送实际的请求给服务器。
    • 实际请求中包含了正常的请求方法(例如GET、POST、PUT等)、请求头和请求体等信息。
    • 服务器收到实际请求后,会处理请求并返回相应的响应给浏览器。

下图展示了跨域请求的流程:

     +-------------+         +-------------+|    Browser  |         |    Server   |+-------------+         +-------------+|                        || 1. 发送预检请求        |+----------------------->||                        || 2. 接收预检响应        ||<-----------------------+|                        || 3. 发送实际请求        |+----------------------->||                        || 4. 接收实际响应        ||<-----------------------+

总的来说,跨域请求的流程就是浏览器先发送预检请求询问服务器是否允许跨域请求,然后根据服务器的响应决定是否发送实际请求。如果预检请求得到了服务器的允许,浏览器才会发送实际的请求。

跟着这个OPTIONS请求查找:

发现,只需要我把这个请求过滤掉即可,让它可以实际请求,使得我的自定义请求头 - 特定的请求头(access-control-request-headers=content-type,headeruserid,headerusertoken)可以接收到我就可以进行判断了。

if ("OPTIONS".equals(request.getMethod().toUpperCase())) {return true;
}

有效果,解决了。

在这里插入图片描述

三、拓展

此处是使用的@CrossOrigin(origins = "*")注解同时过滤掉OPTIONS请求实现了跨域

还可以通过只设置一个跨域过滤器解决跨域问题

下列方法转载于博客园作者小泉哥

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;/*** 全局跨域配置类* 跨域请求的配置,允许所有来源的跨域请求* * 跨域请求流程:* 1. 浏览器发送预检请求(OPTIONS请求)给服务器,询问是否允许实际请求中包含特定的自定义请求头字段和请求方法。* 2. 服务器根据预检请求的信息判断是否允许实际请求,发送适当的CORS响应头给浏览器。* 3. 如果预检请求得到了服务器的允许,浏览器发送实际的请求给服务器。* 4. 服务器收到实际请求后,处理请求并返回相应的响应给浏览器。* * 注:当设置allowCredentials为true时,Access-Control-Allow-Origin响应头不能使用通配符"*",而是必须明确指定允许的来源。* * @author red-velvet* @since 2024/2/8*/
@Configuration
public class GlobalCorsConfig {/*** 配置CorsFilter* @return CorsFilter*/@Beanpublic CorsFilter corsFilter() {// 创建CorsConfiguration对象,配置CORS跨域规则CorsConfiguration config = new CorsConfiguration();// 允许所有来源的跨域请求config.addAllowedOrigin("*");// 允许携带凭据(例如Cookie)config.setAllowCredentials(false);// 允许所有请求方法的跨域请求config.addAllowedMethod("*");// 允许所有请求头的跨域请求config.addAllowedHeader("*");// 创建UrlBasedCorsConfigurationSource对象,注册CORS配置UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();configSource.registerCorsConfiguration("/**", config);// 创建CorsFilter对象,传入配置源return new CorsFilter(configSource);}
}
dCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();configSource.registerCorsConfiguration("/**", config);// 创建CorsFilter对象,传入配置源return new CorsFilter(configSource);}
}

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

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

相关文章

如何写好一个简历

如何编写求职简历 论Java程序员求职中简历的重要性 好简历的作用 在求职过程中&#xff0c;一份好的简历是非常重要的&#xff0c;它甚至可以直接决定能否被面试官认可。一份出色或者说是成功的个人简历&#xff0c;最根本的作用是能让看这份简历的人产生一定要见你的强烈愿…

Idea Git Review插件

idea git plugin 添加了一些常用的小插件 可以右键打开git bash窗口 可以右键选中文字点击baidu fanyi 可以通过搜索git用户名 指定开始时间查询某个版本自己提交的所有代码文件 可以通过点击蓝色行数&#xff0c;跳转到指定的改动代码块 资源地址&#xff1a; git-pl…

伦敦金是现货黄金吗?

伦敦金属现货黄金交易的一种形式。投资者可以通过伦敦金市场直接买卖黄金&#xff0c;以实现投资收益。伦敦金市场具有高度流动性和透明度&#xff0c;是全球投资者广泛参与的贵金属交易市场之一。 什么是现货黄金&#xff1f; 现货黄金是指实物黄金的交易&#xff0c;投资者可…

C/C++模板初阶

目录 1. 泛型编程 2. 函数模板 2.1 函数模板概念 2.1 函数模板格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.5 模板参数的匹配原则 3. 类模板 3.1 类模板的定义格式 3.2 类模板的实例化 1. 泛型编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int&…

百面嵌入式专栏(面试题)驱动开发面试题汇总 2.0

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将介绍驱动开发面试题 。 1、Linux系统的组成部分? Linux内核、Linux文件系统、Linux shell、Linux应用程序。 2、Linux内核的组成部分? (1)第一种分类方式:内存管理子系统、进程管理子系统、文件管理子系…

[C#]winform制作仪表盘好用的表盘控件和使用方法

【仪表盘一般创建流程】 在C#中制作仪表盘文案&#xff08;通常指仪表盘上的文本、数字或指标显示&#xff09;涉及到使用图形用户界面&#xff08;GUI&#xff09;组件&#xff0c;比如Windows Forms、WPF (Windows Presentation Foundation) 或 ASP.NET 等。以下是一个使用W…

【上海大学数字逻辑实验报告】七、中规模元件及综合设计

一、实验目的 掌握中规模时序元件的测试。学会在Quartus II上设计序列发生器。 二、实验原理 74LS161是四位可预置数二进制加计数器&#xff0c;采用16引脚双列直插式封装的中规模集成电路&#xff0c;其外形如下图所示&#xff1a; 其各引脚功能为&#xff1a; 异步复位输…

Microsoft Excel 加载数据分析工具

Microsoft Excel 加载数据分析工具 1. 打开 Excel&#xff0c;文件 -> 选项2. 加载项 -> 转到…3. 分析工具库、分析工具库 - VBA4. 打开 Excel&#xff0c;数据 -> 数据分析References 1. 打开 Excel&#xff0c;文件 -> 选项 2. 加载项 -> 转到… ​​​ 3…

【Linux】线程概念和线程控制

线程概念 一、理解线程1. Linux中的线程2. 重新定义线程和进程3. 进程地址空间之页表4. 线程和进程切换5. 线程的优点6. 线程的缺点7. 线程异常8. 线程用途9. 线程和进程 二、线程控制1. pthread 线程库&#xff08;1&#xff09;pthread_create()&#xff08;2&#xff09;pth…

《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)

文章目录 1.1 MySQL 概览&#xff1a;版本、特性和生态系统1.1.1 基础知识1.1.2 重点案例&#xff1a;使用 Python 实现 MySQL 数据的 CRUD 操作1.1.3 拓展案例 1&#xff1a;使用 Python 实现 MySQL 数据备份**1.1.4 拓展案例 2&#xff1a;使用 Python 分析 MySQL 数据 1.2 安…

例39:使用List控件

建立一个EXE工程&#xff0c;在窗体上放一个文本框&#xff0c;一个列表框和三个按钮输入如下的代码&#xff1a; Sub Form1_Command1_BN_Clicked(hWndForm As hWnd, hWndControl As hWnd)List1.AddItem(Text1.Text)End SubSub Form1_Command2_BN_Clicked(hWndForm As hWnd, h…

算法学习——LeetCode力扣回溯篇1

算法学习——LeetCode力扣回溯篇1 77. 组合 77. 组合 - 力扣&#xff08;LeetCode&#xff09; 描述 任何顺序 返回答案。 示例 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 示例 2&#xff1a; 输…

steam搬砖项目,“一个月赚8K+”真的假的?

在游戏中&#xff0c;搬砖党是永远都不能忽视的存在&#xff0c;随着游戏产业的不断发展&#xff0c;普通人也可以在steam搬砖项目中找到自己的生财之道。由于是低技术的重复工作&#xff0c;和现实的搬砖类似&#xff0c;所以才叫steam搬砖项目。 steam搬砖项目其实就和pdd无…

数据结构(C语言)代码实现(八)——顺序栈实现数值转换行编辑程序括号分配汉诺塔

目录 参考资料 顺序栈的实现 头文件SqStack.h&#xff08;顺序栈函数声明&#xff09; 源文件SqStack.cpp&#xff08;顺序栈函数实现&#xff09; 顺序栈的三个应用 数值转换 行编辑程序 顺序栈的实现测试 栈与递归的实现&#xff08;以汉诺塔为例&#xff09; 参考资…

2024-02-13 Unity 编辑器开发之编辑器拓展4 —— EditorGUIUtility

文章目录 1 EditorGUIUtility 介绍2 加载资源2.1 Eidtor Default Resources2.2 不存在返回 null2.3 不存在则报错2.4 代码示例 3 搜索框查询、对象选中提示3.1 ShowObjectPicker3.2 PingObject3.3 代码示例 4 窗口事件传递、坐标转换4.1 CommandEvent4.2 GUIPoint 和 ScreenPoi…

Vue源码系列讲解——模板编译篇【三】(HTML解析器)

目录 1. 前言 2. HTML解析器内部运行流程 3. 如何解析不同的内容 3.1 解析HTML注释 3.2 解析条件注释 3.3 解析DOCTYPE 3.4 解析开始标签 3.5 解析结束标签 3.6 解析文本 4. 如何保证AST节点层级关系 5. 回归源码 5.1 HTML解析器源码 5.2 parseEndTag函数源码 6. …

【快速上手QT】02-学会查看QT自带的手册QT助手

QT助手 为什么大家都说QT简单&#xff0c;第一点就是确实简单&#xff08;bushi&#xff09;。 我个人觉得最关键的点就是人家QT官方就给你准备好了文档&#xff0c;甚至还有专门的IDE——QtCreator&#xff0c;在QTCreator里面还有很多示例代码&#xff0c;只要你会C的语法以…

ETL是什么,有哪些ETL工具?就业前景如何?

ETL是什么 ETL&#xff08;Extract-Transform-Load&#xff09;&#xff0c;用来描述将数据从来源端经过抽取(extract)、转换(transform)、加载(load)至目标端的过程。ETL一词较常用在数据仓库&#xff0c;但其对象并不限于数据仓库。它可以自动化数据处理过程&#xff0c;减少…

2024.2.3 作业

1、实现单向循环链表的头插头删尾插尾删 #include<stdio.h> #include<string.h> #include<stdlib.h> typedef int datatype; typedef struct node {//数据域int data;//指针域struct node *next; }*Linklist; Linklist create() {Linklist s(Linklist)mallo…

如何在C# Windows Forms应用程序中实现控件之间的连接线

帮我实现绘图工具多个控件连接线&#xff0c;请用c#代码实现 实现绘图工具中多个控件之间的连接线功能&#xff0c;可以通过以下几个步骤来进行&#xff1a; 定义连接线的数据模型&#xff1a;首先需要定义一个模型来表示连接线&#xff0c;这个模型应该包含起点和终点的坐标。…