首页 > 其他分享 >详解前端中的跨域及解决措施

详解前端中的跨域及解决措施

时间:2024-09-06 10:51:36浏览次数:8  
标签:http 跨域 前端 响应 详解 let 服务器 请求

1、跨越介绍

1.1、概念

  1. 概念:跨域是浏览器同源策略产生的一个限制
  2. 同源策略
    • 浏览器制定的一个安全策略,这个安全策略的主要目标是:不让我们向别人的服务器发起请求
    • 同源策略要求:同域名同端口号同协议不符合同源策略的,浏览器为了安全会阻止这个请求

1.2、如何界定服务器是自己的还是别人的

  1. 查看请求的 "协议/端口/域名" 这3个内容和请求源(当前打开页面的"协议/端口/域名")是否相同
  2. 如果三者有一者不同,那么就会触发跨域错误

1.3、常见源

  1. 常见源1:file:///E:/——没有域名/端口 => 本地磁盘的路径
  2. 常见源2:http://127.0.0.1:5500/——协议是:http,域名是:127.0.0.1,端口是:5500 => 在服务器打开的路径

1.4、如何解决跨域错误

  1. 注意:如果服务端不想给跨域请求数据,那么我们解决不了跨域问题
  2. 跨域这件事其实主导者还是在服务端,如果服务端允许我们的跨域请求,那么就可以发起跨域请求,反之就不能发起请求

1.5、示例跨域错误

let btn = document.querySelector("#btn");
btn.addEventListener( "click" , function(){
  // 演示:向百度发起一个ajax请求 => 这里的演示只要是和当前源的协议、端口、域名不一致的即可 
  fetch("https://www.baidu.com")
  // 报错:报错信息中的No 'Access-Control-Allow-Origin'这段话表示ajax请求是违背了同源策略的,此时不可以发送ajax请求
})

2、解决跨域——JSONP

2.1、解释

把原本的ajax请求——替换成:在"script"标签"src"属性发起请求

  1. 示例
    • <script src="https://www.baidu.com"><script>——向百度发起请求
  2. 解释
    • 如果我们定义了一个带有src属性的script标签,那么浏览器就会根据script标签的src属性发起请求
    • 注意1:我们当前发起的请求,它的响应数据会被当成js来执行!要求响应数据必须符合js代码执行标准,是有意义的js代码 => 告知服务端给我们返回的响应数据必须是有意义的js代码
    • 注意2:我们当前发起的请求,请求方式只能是get => 因为script标签发出去的请求没有什么危害性,也算是ajax请求的"阉割版"
  3. 和ajax请求的区别
    • 发起的请求响应会被当作js代码立即执行,而ajax返回的请求响应是被放在对象中的一条属性
    • ajax可以任意使用请求方式
  4. 查看请求是否发送
    • 在网络请求部分将过滤分页调成js
    • 左侧的请求图标是黄色的——把百度的代码当成js来解释

2.2、注意

  1. 当前的script标签请求会在页面打开后就立即发送
  2. 这会导致有了响应数据后,如果没有全局函数会报错,所以这种请求一定要放在全局函数创建后,再进行请求发起!

2.3、面试

  1. 问题:jsonp原理
  2. 回答:动态创建script标签,src属性指向没有跨域限制

2.4、示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>demo-1</title>
</head>
<body>
  <!-- 1、先设置好回调函数 -->
    <script>
        function callback(data){
          console.log(data);
        }
    </script>
  
  <!-- 2、发送jsonp请求并携带数据 -->
    <script src="https://www.baidu.com/sugrec?prod=pc&from=pc_web&wd=你好&cb=callback"></script>
</body>
</html>

3、解决跨域——CORS跨域

3.1、简述概念

  1. CORS跨域
    • CORS是在服务端返回响应的时候,向响应头中添加可以跨域访问的响应头信息实现的 => 在服务端添加响应头实现的跨域方案
    • 在条件允许的情况下,尽可能的使用CORS的跨域会比较好
  2. 问题:向目标服务器发起请求:http://localhost:8889报错
    • 解释:如果用当前页面(open in default browser / live server)发起请求就会产生跨域问题,因为和目标服务器的路径不一致
    • 解决:
      • 注意1:要先开启测试服务器,再通过当前页面向测试服务器发起请求 => 另外:使用CORS跨域的时候,服务端必须是我们自己写的 (或者跟后端沟通,让他改一下响应头的配置项),因为要能改服务端的代码才可以,用别人的端口实现CORS跨域不太可能
      • 我们需要配置服务器响应头,才可以实现跨域的数据访问
      • 注意2:如果服务端启用了CORS跨域,我们可以使用所有前端的ajax技术

3.2、示例客户端代码

// 1、获取页面元素的dom对象
        let btn = document.getElementById("btn");
// 3、编写事件处理函数
        async function sendRequest(){
            let response = await fetch("http://localhost:8889");
            let data = await response.json();
            console.log( data ); // 在没有设置响应头时,点击发送请求是报错的
        }
// 2、给元素添加事件
        btn.addEventListener("click" , sendRequest)

// 4、设置服务器响应头步骤——这里可以用小伙伴们自己得服务端代码,写入这行代码即可
        // 写入:res.setHeader("Access-Control-Allow-Origin" , "*")即可

3.3、示例服务端代码

let http  = require("http");
let chalk = require("chalk");
let server = http.createServer( ( req , res ) => {
    // 注意:在这里使用响应头添加工具,添加CORS跨域响应头  
    // res.setHeader( 响应头key"Access-Control-Allow-Origin" , 响应头value"*" );
    // 配置项 => "Access...:允许哪一个地址去进行跨域请求"
    // 地址信息 => "*":所有地址都行;也可以写 http://127.0.0.1:5500/这种,但是这种完整的路径需要携带协议(http/其它协议)
    res.setHeader("Access-Control-Allow-Origin" , "*"); 
 
    // 响应数据
    let data = {
        "message": "我已经接受到了你的请求, 这是我给你的回应, 我是一个 json 格式",
        "tips": "后端返回给前端的数据",
        "code": 1,
    }
    // 响应头设置(否则无法正常显示中文)
    res.setHeader("Content-Type" , "text/html;charset=utf8");
    // 将数据写入响应体
    res.write( JSON.stringify(data) );
    // 结束响应
    res.end();
})

server.listen(8889 , ()=>{
  const port = server.address().port
  const text = 
  `
    恭喜你,服务器启动成功啦 ${ chalk.cyan('^_^') }!
    目前正在监听 ${ chalk.red(port) } 端口号!
    基准地址: ${ chalk.red('http://localhost:' + port) }
  `
  console.log(text)
});

4、解决跨域——服务器代理跨域

4.1、简述概念

  1. 服务器代理跨域就是在本地开启一个服务器,代理发送我们的请求
  2. 可以实现跨域的原因是:因为同源策略是给浏览器设置的,对服务器不生效,所以我们的服务器代理跨域是不受同源策略限制的

4.2、示例客户端代码

<body>
    <button id="btn">向百度接口发起请求</button>
    <button id="btn2">向代理服务器发起请求</button>

<script>
    // 测试是否可以直接向百度发起请求 => 不能,会报错
        let btn = document.getElementById("btn");
        function sendRequest(){
            fetch("https://www.baidu.com/sugrec")
        }
        btn.addEventListener("click" , sendRequest )

    // 根据代理服务器(proxy-server.js)——测试代理请求
        let btn2 = document.getElementById("btn2");
        async function sendProxyRequest(){
            // 1、此时我们的代理请求就是 => 给本地的代理服务器发请求,具体服务器怎么做那是服务器的事了 
            let response = await fetch("http://localhost:8890"); // 2、给我们自己配置的本地服务器发送请求,让它替我们向百度发请求
                   // 3、注意:如果本地服务器没设置cors跨域的话,一样会报错,所以不要忘记在proxy-server.js配置响应头,先实现能给自己的服务器发送请求,再让它代替我们发请求
            let data = await response.json();
            console.log( data );
        }
        btn2.addEventListener("click" , sendProxyRequest )
</script>
</body>

4.3、示例服务端代码

let http  = require("http");
let chalk = require("chalk");
let axios = require("axios");

let server = http.createServer(async ( req , res ) => {
    // 代理服务器配置cors跨域
    res.setHeader("Access-Control-Allow-Origin" , "*"); 

    // 配置请求信息
    let options = {
      params : {
        prod : "pc",
        from : "pc_web", 
        wd : "hello world" ,
        // !发起的请求可以不带cb => 因为这是服务器端
      }
    }
    // 使用axios根据路径进行请求配置: 
    let { data } = await axios("https://www.baidu.com/sugrec" , options )
    // 响应头设置 => 否则无法正常显示中文
    // 响应头设置 => 否则无法正常显示中文
    res.setHeader("Content-Type" , "text/html;charset=utf8");
    // 将数据写入响应体 
    res.write( JSON.stringify(data) );
    // 结束响应
    res.end();
})

server.listen(8890 , ()=>{
  const port = server.address().port
  const text = `
    恭喜你, 服务器启动成功啦 ${ chalk.cyan('^_^') } !
    目前正在监听 ${ chalk.red(port) } 端口号 !
    基准地址: ${ chalk.red('http://localhost:' + port) }
  `
  console.log(text)
});

4.4、服务器代理原理示例图

在这里插入图片描述

标签:http,跨域,前端,响应,详解,let,服务器,请求
From: https://blog.csdn.net/2301_78675670/article/details/141923164

相关文章

  • 后台返回pdf文件流,前端实现在线预览和下载
    预览功能用到的data值:点击查看代码data(){return{fileUrl:null,dialogTitlePdf:'',dialogVisiblePdf:false,disabledPdf:false,}}预览的弹框:点击查看代码<el-dialog:title="dialogTitlePdf"......
  • node通过ffmpeg将多路rtsp、rtmp流媒体转换为多端口websocket流供前端播放
    node通过ffmpeg将多路rtsp、rtmp流媒体转换为多端口websocket流供前端播放这里写目录标题node通过ffmpeg将多路rtsp、rtmp流媒体转换为多端口websocket流供前端播放1安装node2安装ffmpeg3【重要】使用node搭建rtsp、rtmp转码服务器(必须要提前安装ffmpeg)4前端(vue3)播......
  • Java高级编程—多线程(完整详解线程的三种实现方式、以及守护线程、出让线程、插入线程
    二十八.多线程文章目录二十八.多线程28.1线程的三种实现方式28.1.1第一种28.1.2第二种28.1.3第三种28.2常见的成员方法28.3守护线程28.4出让线程28.5插入线程28.6线程生命周期28.7同步代码块28.8同步方法28.1线程的三种实现方式继承Thread类的方式进行......
  • Flask:Python轻量级Web框架详解
    Flask是一个用Python编写的轻量级Web应用框架。它被设计为易于使用和扩展,非常适合小型项目和微服务,同时也能够支持大型应用。Flask依赖于少量的外部库,并且提供了一个简单的方式来创建Web应用。Flask的主要特点轻量级:Flask核心非常简单,使得它易于理解和扩展。扩展性:Flask可......
  • Python异步编程:asyncio库详解
    \asyncio是Python的标准库,用于编写单线程的并发代码。它使用async和await语法来定义和调用异步函数,使得I/O密集型程序能够更有效地使用资源。asyncio的主要特点事件循环:asyncio程序由事件循环驱动,它负责调度协程的执行。协程:使用async定义的异步函数被称为协程。任务:asyn......
  • 拨码开关详解
    拨码开关详解拨码开关简介拨码开关(也叫DIP开关,拨动开关,超频开关,地址开关,拨拉开关,数码开关,指拨开关)是一款用来操作控制的地址开关,采用的是0/1的二进制编码原理。拨码开关多数用于程序控制板块,控制元器件性能电路导通断开。所以拨码开关也会根据行业板块称呼为:程序开关、地址开......
  • netstat命令详解
    ‌‌netstat命令是一个强大的网络工具,用于显示网络连接、‌路由表、‌接口统计等信息。‌通过使用不同的参数组合,用户可以获取关于网络活动的详细信息。以下是netstat命令的一些常用参数及其功能:‌‌-a(all)‌:显示所有选项,包括已建立的连接和监听状态的连接。‌-n‌:以数......
  • Postman请求参数:Query、Path、Body 详解
    Postman作为一个功能强大的工具,极大地简化了API测试和调试的过程,提供了发送请求和检查响应的直接方法。本文将着重介绍如何在Postman中高效地处理请求参数,以提高API测试和开发的便利性。1、解析请求参数首先,我们需要明白什么是请求参数。简单来说,请求参数是传递......
  • Kubernetes容器生命周期详解:PostStart和PreStop应用案例解析
    1.容器启动命令:容器启动命令指在容器启动时需要执行的命令。通过设置ENTRYPOINT或CMD,可以自定义容器启动时执行的进程。使用了一个简单的Dockerfile来设置ENTRYPOINT命令:FROMubuntuENTRYPOINT["top","-b"]该命令告诉容器启动时运行top命令,并且以-b选项进行批量模式......
  • mysqldump命令详解
    在日常维护工作当中经常会需要对数据进行导出操作,而mysqldump是导出数据过程中使用非常频繁的一个工具;它自带的功能参数非常多,文章中会列举出一些常用的操作,在文章末尾会将所有的参数详细说明列出来。 语法:默认不带参数的导出,导出文本内容大概如下:创建数据库判断语句-删除表-......