前端访问后端实现跨域

news2024/11/22 16:26:08

背景:前端在抖音里做了一个插件然后访问我们的后端。显然在抖音访问其他域名肯定会跨域。

解决办法:

1、使用比较简单的jsonp

JSONP

优点:JSONP 是通过动态创建 <script> 标签的方式加载外部数据,属于跨域数据请求的一种传统解决方案。JSONP 不会受到浏览器的同源策略限制,因此在某些跨域环境(如抖音小程序中)可以正常工作。

缺点:只能进行 GET 请求,无法支持 POST、PUT 等其他 HTTP 方法。

安全性较低,因为 JSONP 将代码直接注入到页面中,存在潜在的安全风险。

测试案例:

后端 springboot

@RestController
@Slf4j
@RequestMapping("/api")
public class CrosController {

    @GetMapping("/author/info")
    public String crosTest(@RequestParam("authorName") String authorName,
                           @RequestParam(value = "callback", required = false) String callback){
        // 参数校验
        if (authorName == null) {
            return "Invalid request: authorName is required";
        }
        // 模拟返回数据
        String jsonData = "{\"author_id\": 12345, \"author_name\": \"" + authorName + "\"}";

        // 判断是否为 JSONP 请求
        if (callback != null && !callback.isEmpty()) {
            // JSONP 响应
            String jsonpResponse = callback + "(" + jsonData + ");";
            return jsonpResponse;
        } else {
            // 普通 JSON 响应
            return jsonData;
        }
    }

}

前端html页面

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

</body>

</html>

<script>
 function jsonpRequest(url, params, callbackName) {
  return new Promise((resolve, reject) => {
    // 动态创建回调函数名称
    const uniqueCallback = callbackName || `jsonpCallback_${Date.now()}`;

    // 将回调函数注册到全局对象中
    window[uniqueCallback] = function (response) {
      // 清理全局回调函数和 script 标签
      delete window[uniqueCallback];
      document.body.removeChild(script);

      // 返回响应数据
      resolve(response);
    };

    // 构建完整的 URL(拼接参数)
    const query = Object.entries(params)
      .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
      .join("&");
    const fullUrl = `${url}?${query}&callback=${uniqueCallback}`;

    // 创建 script 标签
    const script = document.createElement("script");
    script.src = fullUrl;

    // 处理加载失败
    script.onerror = function () {
      delete window[uniqueCallback];
      document.body.removeChild(script);
      reject(new Error("JSONP request failed"));
    };

    // 插入 script 标签到文档中
    document.body.appendChild(script);
  });
}

// 使用示例
const url = "http://localhost:8080/api/author/info";
const params = { authorName: "烟火中的水滴" };

jsonpRequest(url, params)
  .then((data) => {
    console.log("Author Info:", data);
  })
  .catch((error) => {
    console.error("Error:", error);
  });

</script>

然后打开次页面。
1、打开控制台 2、执行 可以看到结果正常返回了

jsonpRequest(url, params)
  .then((data) => {
    console.log("Author Info:", data);
  })
  .catch((error) => {
    console.error("Error:", error);
  });

在这里插入图片描述

2、@CrossOrigin 解决跨域

Spring Boot 的 @CrossOrigin 注解用于配置 CORS(跨域资源共享),它允许你的后端接受来自其他域的请求。

优点:CORS 是更现代、更安全的跨域解决方案,相比 JSONP,支持所有 HTTP 方法(如 GET、POST 等)。安全性高,因为 CORS 会进行严格的域名、方法等验证。
缺点:如果客户端(如抖音小程序)对 CORS 的处理有限,可能无法支持复杂的预检请求(如 OPTIONS 请求)。CORS 依赖浏览器的支持,如果环境对跨域限制较为严格(如一些小程序环境),可能 CORS 不生效。
我们先开启后端运行起来。看一些问题

1、通过控制台源null模拟跨域

后端代码

@RestController
@Slf4j
@RequestMapping("/api")
public class CrosController {
    @GetMapping("/author/info/cross")
    public String crossTest(@RequestParam("authorName") String authorName){
        // 参数校验
        if (authorName == null) {
            return "Invalid request: authorName is required";
        }
        // 模拟返回数据
        String jsonData = "{\"author_id\": 12345, \"author_name\": \"" + authorName + "\"}";
        return jsonData;
    }

}

1、通过curl
请求
curl 'http://localhost:8080/api/author/info/cross?authorName=123'
结果
{"author_id": 12345, "author_name": "123"}
这个属于正常的
2、打开一个index.html 然后控制台通过 前端代码访问这个接口

fetch('http://localhost:8080/api/author/info?authorName=烟火中的水滴')
 .then(response => response.json())
 .then(data => console.log("JSON Response:", data))
 .catch(error => console.error("Error:", error));

发现报错
在这里插入图片描述
问题分析
错误提示:
No ‘Access-Control-Allow-Origin’ header is present on the requested resource 表示目标服务器(http://localhost:8080)没有返回允许跨域访问的CORS响应头。
浏览器的安全机制会拦截请求响应。
根本原因:
客户端代码运行的index.html被浏览器认为是从null源加载的(例如直接从文件系统打开),与http://localhost:8080是不同源。
目标服务器未配置CORS。
其实这个就是跨域了因为你从一个控制台打开访问8080端口 但是你不是同源的就会报错。
那么解决办法就是加一个注解

 @CrossOrigin(origins = "*") // 允许指定来源跨域
    @GetMapping("/author/info/cross")
    public String crossTest(@RequestParam("authorName") String authorName){
        // 参数校验
        if (authorName == null) {
            return "Invalid request: authorName is required";
        }
        // 模拟返回数据
        String jsonData = "{\"author_id\": 12345, \"author_name\": \"" + authorName + "\"}";
        return jsonData;
    }

重新访问
fetch('http://localhost:8080/api/author/info/cross?authorName=烟火中的水滴') .then(response => response.json()) .then(data => console.log("JSON Response:", data)) .catch(error => console.error("Error:", error))
成功了
在这里插入图片描述
我们看下他发起的curl请求参数:

curl 'http://localhost:8080/api/author/info/cross?authorName=%E7%83%9F%E7%81%AB%E4%B8%AD%E7%9A%84%E6%B0%B4%E6%BB%B4' \
  -H 'Accept: */*' \
  -H 'Accept-Language: zh-CN,zh;q=0.9' \
  -H 'Connection: keep-alive' \
  -H 'Origin: null' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: cross-site' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"'

源是null实际也属于跨域的。
上面是的源是null 我们接下来用python模拟一个源请求
模拟跨域,就得开启一个前端服务器 然后请求后端。

2、模拟前端服务器 端口3000实现跨域

使用 Python(自带)启动 HTTP 服务器: 在终端中进入你的 index.html 所在的目录,并运行以下命令:
python -m http.server 3000
在这里插入图片描述

这会在 localhost:3000 上启动一个 HTTP 服务器。然后在浏览器中访问:
然后打开浏览器 访问 http://localhost:3000/index.html
打开控制台执行
fetch('http://localhost:8080/api/author/info/cross?authorName=烟火中的水滴') .then(response => response.json()) .then(data => console.log("JSON Response:", data)) .catch(error => console.error("Error:", error))
在这里插入图片描述
最后我们打开Network看下他发起的请求是不是真的跨域了。
通过查看curl命令确实跨域了

curl 'http://localhost:8080/api/author/info/cross?authorName=%E7%83%9F%E7%81%AB%E4%B8%AD%E7%9A%84%E6%B0%B4%E6%BB%B4' \
  -H 'Accept: */*' \
  -H 'Accept-Language: zh-CN,zh;q=0.9' \
  -H 'Connection: keep-alive' \
  -H 'Origin: http://localhost:3000' \
  -H 'Referer: http://localhost:3000/' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-site' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"'

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

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

相关文章

《Vue零基础入门教程》第二课:搭建开发环境

往期内容&#xff1a; 《Vue零基础入门教程》第一课&#xff1a;Vue简介 1 搭建开发环境 Vue环境分为两种 不使用构建工具使用构建丁具 首先&#xff0c;我们会介绍 不使用构建工具 的环境,在组件化章节中介绍 使用构建工具 的方式 1) 初始化 使用如下指令初始化 npm i…

快速排序【hoare版】

目录 介绍 算法思路 函数实现 函数声明 确定基准值 创建新函数 创建循环找数据&#xff08;right&#xff0c;left&#xff09; 交换左右数据 交换条件设置 外部循坏条件设置 初步总结代码 循环条件完善 内层循环的完善 外层循环的完善 相遇值大于keyi 相遇值等于k…

oracle导入线上数据的全步骤

多租户架构允许oracle数据库成为一个多租户的容器数据库&#xff0c;也就是CDB&#xff0c;container database&#xff0c;与之相对应的&#xff0c;则是插入到这个容器里面的可插拔式数据库&#xff0c;pluggable database 一个CDB可以包含0&#xff0c;1或者多个用户创建的…

嵌入式硬件实战基础篇(三)-四层板PCB设计-步进电机驱动(TMC2208/TMC2209)

引言&#xff1a;我们在嵌入式硬件杂谈&#xff08;三&#xff09;中有提到阻抗匹配的问题&#xff0c;也引入了高速PCB设计的思想&#xff0c;并且此篇实战基础篇主要是基础的四层板的绘制设计&#xff0c;后续实战会对高速板展开&#xff0c;本篇主要是提升读者的设计PCB板的…

uniapp 选择 省市区 省市 以及 回显

从gitee仓库可以拿到demo 以及 json省市区 文件 // 这是组件部分 <template><uni-popup ref"popup" type"bottom"><view class"popup"><view class"picker-btn"><view class"left" click"…

C语言练习.while语句

题目&#xff1a; 1.用C语言编程&#xff0c;运用while语句&#xff0c;写一段简短的代码。 分析&#xff1a; 1.运用while语句要注意&#xff1a;while语句&#xff0c;要设置好退出条件&#xff0c;不然就会造成无限循环的结果&#xff0c;导致程序停不下来。 2.编写代码…

Linux编辑器 - vim

目录 一、vim 的基本概念 1. 正常/普通/命令模式(Normal mode) 2. 插入模式(Insert mode) 3. 末行模式(last line mode) 二、vim 的基本操作 三、vim 正常模式命令集 1. 插入模式 2. 移动光标 3. 删除文字 4. 复制 5. 替换 6. 撤销上一次操作 7. 更改 8. 调至指定…

24.11.20 sevlet2

1.servlet是否线程安全 (线程特性) 线程安全的指标 //1.是否有共享数据 //2.多线程对共享数据做写操作 servlet中 不要创建成员变量 servlet是单实例的 所以成员变量(不加static) 就会在多线程间共享 如果service()方法中 对成员变量有写操作 则线程不安全 servlet中非特殊情…

【编译器】Dev C++建立C语言工程

【编译器】Dev C建立C语言工程 文章目录 [TOC](文章目录) 前言一、创建工程二、添加.c.h三、主函数处理四、在桌面中打开exe文件五、参考资料总结 前言 在使用了很多编译器之后&#xff0c; 要么是太大了&#xff0c; 要么是太新了&#xff0c; 要么是在线编译器&#xff0c;用…

【ArcGIS微课1000例】0132:从多个GIS视角认识与攀登珠穆朗玛峰

文章目录 1. Map Viewer中打开2. 场景查看器中打开3. ArcGIS中打开4. QGIS中打开5. Globalmapper中打开6. ArcGIS Earth中打开官网地址:https://www.arcgis.com/home/item.html?id=504a23373ab84536b7760c0add1e0c1c 1. Map Viewer中打开 以下展示不同底图样式的珠穆朗玛峰壮…

vscode uniapp 微信小程序 view、text、image标签红色波浪线

没修改前的红色波浪线样式 看好多人没解决方法&#xff0c;我的这种反正成功了&#xff0c;解决方法如下&#xff1a;首先降级Vue - Official 为 v2.0.12 选择版本 配置tsconfig.json "vueCompilerOptions": {// experimentalRuntimeMode 已废弃&#xff0c;现调整为…

SCTransNet验证测试

SCTransNet 是PRCV 2024、ICPR 2024 Track 1、ICPR 2024 Track 2 三项比赛冠军方案的 Baseline, 同时也是多个优胜算法的Baselines. Bilibili 视频分享 【工作分享】SCTransNet:面向红外弱小目标检测的空间 - 通道交叉 Transformer_哔哩哔哩_bilibili 极市平台 推文分享 …

电路模型和电路定理(二)

电路元件 是电路中最基本的组成单元。 电阻元件&#xff1a;表示消耗电能的元件 电感元件&#xff1a;表示产生磁场&#xff0c;储存磁场能的元件 电容元件&#xff1a;表示产生电场&#xff0c;储存电场能量的元件 电压源和电流源&#xff1a;表示将其他形式的能量转变成…

2023AE软件、Adobe After Effects安装步骤分享教程

2023AE软件是一款由Adobe公司开发的视频编辑软件&#xff0c;也被称为Adobe After Effects。它在广告、电影、电视和网络视频等领域广泛应用&#xff0c;用于制作动态图形、特效、合成和其他视觉效果。该软件支持多种视频和音频文件格式&#xff0c;具有丰富的插件和预设&#…

AI Large Language Model

AI 的 Large Language model LLM , 大语言模型&#xff1a; 是AI的模型&#xff0c;专门设计用来处理自然语言相关任务。它们通过深度学习和庞大的训练数据集&#xff0c;在理解和生成自然语言文本方面表现出色。常见的 LLM 包括 OpenAI 的 GPT 系列、Google 的 PaLM 和 Meta…

【大数据学习 | Spark】关于distinct算子

只有shuffle类的算子能够修改分区数量&#xff0c;这些算子不仅仅存在自己的功能&#xff0c;比如分组算子groupBy&#xff0c;它的功能是分组但是却可以修改分区。 而这里我们要讲的distinct算子也是一个shuffle类的算子。即可以修改分区。 scala> val arr Array(1,1,2,…

SrpingBoot基础

SpringBoot基本框架中重要常用的包讲解: .idea包和.mvn包框架生成不经常用 src包下主要存放前后端代码: main包下的java包存放的是后端java代码主要负责数据处理 resource包下存放的是配置资源和前端页面,其中static中存放的是前端html网页一般存放静 态资源,templates包…

Spring6 MyBatis

1. 依赖 <dependencies><!-- spring核心--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.1.14</version></dependency><!-- Resource注解的依赖…

JavaEE专栏介绍

专栏导读 在当今快速发展的信息技术时代&#xff0c;JavaEE作为企业级应用开发的核心技术之一&#xff0c;扮演着至关重要的角色。本“JavaEE”专栏旨在为对JavaEE感兴趣的开发者提供一个全面的学习平台&#xff0c;从基础概念到高级应用&#xff0c;帮助读者深入理解JavaEE框…

互联网数字化商品管理浪潮思考:从信息化到精准运营

目录 一、商品数字化转型面临的现状分析 &#xff08;一&#xff09;运营方向分析 &#xff08;二&#xff09;商品归类分析 二、商品数字化管理建设分析 三、基础建设——商品信息数字化 &#xff08;一&#xff09;商品信息质量数字化的目的 &#xff08;二&#xff0…