CORS 跨域资源共享 与 JSONP

news2025/1/11 12:24:34

CORS 

1、接口的跨域问题

  • 我们使用express编写的 GET POST接口,存在一个很严重的问题:不支持跨域请求
  •  解决接口跨域问题的方案主要有两种:
    • CORS(主流的解决方案,推荐使用
    • JSONP(有缺陷的解决方案:只支持 GET 请求)

2、使用 cors 中间件解决跨域问题

        cors Express 的一个第三方中间件。通过安装和配置 cors 中间件,可以很方便地解决跨域问题。

使用步骤分为如下 3 步:

  • 运行 npm install cors 安装中间件
  • 使用 const cors = require('cors') 导入中间件
  • 在路由之前调用 app.use(cors()) 配置中间件

 

3、什么是 CORS

        CORS (Cross-Origin Resource Sharing,跨域资源共享)由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器是否阻止前端 JS 代码跨域获取资源

        浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了 CORS 相关的 HTTP 响应头,就可以解除浏览器端的跨域访问限制

 

4、CORS 的注意事项 

  • CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了 CORS 的接口。
  • CORS 在浏览器中有兼容性。只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了 CORS 的服务端接口(例如:IE10+Chrome4+FireFox3.5+)。

5、CORS 响应头部 - Access-Control-Allow-Origin

响应头部中可以携带一个 Access-Control-Allow-Origin 字段,其语法如下:

Access-Control-Allow-Origin: <origin> | *

其中,origin 参数的值指定了允许访问该资源的外域 URL

例如,下面的字段值将只允许来自 http://itcast.cn 的请求:

res.setHeader('Access-Control-Allow-Origin', "http://itcast.cn")

如果指定了 Access-Control-Allow-Origin 字段的值为通配符 *,表示允许来自任何域的请求,示例代码如下:

res.setHeader('Access-Control-Allow-Origin', "*")

6、CORS 响应头部 -

默认情况下,CORS 支持客户端向服务器发送如下的 9 请求头

AcceptAccept-LanguageContent-LanguageDPRDownlinkSave-DataViewport-WidthWidthContent-Type (值仅限于 text/plainmultipart/form-dataapplication/x-www-form-urlencoded 三者之一)

        如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过 Access-Control-Allow-Headers 对额外的请求头进行声明,否则这次请求会失败!

// 允许客户端额外向服务器发送 Content-Type 请求头和 X=Custom-Header 请求头
// 注意:多个请求头之间使用英文的逗号进行分隔
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Custom-Header')

7、CORS 响应头部 - Access-Control-Allow-Methods

  • 默认情况下,CORS 仅支持客户端发起 GETPOSTHEAD 请求。
  • 如果客户端希望通过 PUTDELETE 等方式请求服务器的资源,则需要在服务器端,通过 Access-Control-Alow-Methods指明实际请求所允许使用的 HTTP 方法

示例代码如下:

// 只允许 POST、GET、DELETE、HEAD 请求方法
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE, HEAD')

// 允许所有的 HTTP 请求方法
res.setHeader('Access-Control-Allow-Methods', "*")

8、CORS请求的分类

        客户端在请求 CORS 接口时,根据请求方式请求头的不同,可以将 CORS 的请求分为两大类,分别是:

  • 简单请求
  • 预检请求

9、简单请求

同时满足以下两大条件的请求,就属于简单请求:

  1. 请求方式GETPOSTHEAD 三者之一
  2. HTTP 头部信息不超过以下几种字段:

    ​​​​​​​无自定义头部字段AcceptAccept-LanguageContent-LanguageDPRDownlinkSave-DataViewport-WidthWidth Content-Type(只有三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

10、预检请求

只要符合以下任何一个条件的请求,都需要进行预检请求:

  • 请求方式为 GETPOSTHEAD 之外的请求 Method 类型
  • 请求头中包含自定义头部字段
  • 向服务器发送application/json 格式的数据

        在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTION 请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据

11、简单请求预检请求的区别

  • 简单请求的特点:客户端与服务器之间只会发生一次请求
  • 预检请求的特点:客户端与服务器之间会发生两次请求,OPTION 预检请求成功之后,才会发起真正的请求

JSONP 接口

1、回顾 JSONP概念特点

        概念:浏览器端通过 <script> 标签的 src 属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP

特点:

  • JSONP 不属于真正的 Ajax 请求,因为它没有使用 XMLHttpRequest 这个对象。
  • JSONP 仅支持 GET 请求,不支持 POSTPUTDELETE 等请求。

2、创建 JSONP 接口的注意事项

        如果项目中已经配置了 CORS 跨域资源共享,为了防止冲突必须在配置 CORS 中间件之前声明 JSONP 的接口。否则 JSONP 接口会被处理成开启了 CORS 的接口。示例代码如下:

// 优先创建 JSONP 接口【这个接口不会被处理成 CORS 接口】
app.get('/api/jsonp', (req, res) => { })

// 再配置 CORS 中间件 【后续的所有接口,都会被处理成 CORS 接口】
app.use(cors())

// 这是一个开启了 CORS 的接口
app.get("/api/get", (req, res) => { })

3、实现 JSONP 接口的步骤

  • 获取客户端发送过来的回调函数的名字
  • 得到要通过 JSONP 形式发送给客户端的数据
  • 根据前两步得到的数据,拼接出一个函数调用的字符串
  • 把上一步拼接得到的字符串,响应给客户端的 <script> 标签进行解析执行

4、实现 JSONP 接口的具体代码

// 必须在配置 cors 中间件之前,配置 JSONP 的接口
app.get('/api/jsonp', (req, res) => {
  // TODO: 定义 JSONP 接口具体的实现过程
  // 1. 得到函数的名称
  const funcName = req.query.callback
  // 2. 定义要发送到客户端的数据对象
  const data = { name: 'zs', age: 22 }
  // 3. 拼接出一个函数的调用
  const scriptStr = `${funcName}(${JSON.stringify(data)})`
  // 4. 把拼接的字符串,响应给客户端
  res.send(scriptStr)
})

5、在网页中使用 jQuery 发起 JSONP 请求

调用 $.ajax() 函数,提供 JSONP 的配置选项,从而发起 JSONP 请求,示例代码如下:

   // 为 JSONP 按钮绑定点击事件处理函数
        $('#btnJSONP').on('click', function () {
          $.ajax({
            type: 'GET',
            url: 'http://127.0.0.1/api/jsonp',
            dataType: 'jsonp',  // 表示要发送jsonp请求
            success: function (res) {
              console.log(res)
            },
          })
        })

完整示例代码

router.js

const express = require('express')
const router = express.Router()

// 在这里挂载对应的路由
router.get('/get', (req, res) => {
  // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  const query = req.query
  // 调用 res.send() 方法,向客户端响应处理的结果
  res.send({
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: 'GET 请求成功!', // 状态的描述
    data: query, // 需要响应给客户端的数据
  })
})

// 定义 POST 接口
router.post('/post', (req, res) => {
  // 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
  const body = req.body
  // 调用 res.send() 方法,向客户端响应结果
  res.send({
    status: 0,
    msg: 'POST 请求成功!',
    data: body,
  })
})

// 定义 DELETE 接口
router.delete('/delete', (req, res) => {
  res.send({
    status: 0,
    msg: 'DELETE请求成功',
  })
})

module.exports = router

test.js

// 导入 express
const express = require('express')
// 创建服务器实例
const app = express()

// 配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false }))

// 必须在配置 cors 中间件之前,配置 JSONP 的接口
app.get('/api/jsonp', (req, res) => {
  // TODO: 定义 JSONP 接口具体的实现过程
  // 1. 得到函数的名称
  const funcName = req.query.callback
  // 2. 定义要发送到客户端的数据对象
  const data = { name: 'zs', age: 22 }
  // 3. 拼接出一个函数的调用
  const scriptStr = `${funcName}(${JSON.stringify(data)})`
  // 4. 把拼接的字符串,响应给客户端
  res.send(scriptStr)
})

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require('cors')
app.use(cors())

// 导入路由模块
const router = require('./router')
// 把路由模块,注册到 app 上
app.use('/api', router)

// 启动服务器
app.listen(80, () => {
  console.log('express server running at http://127.0.0.1')
})

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>
    <script src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js"></script>
  </head>
  <body>
    <button id="btnGET">GET</button>
    <button id="btnPOST">POST</button>
    <button id="btnDelete">DELETE</button>
    <button id="btnJSONP">JSONP</button>

    <script>
      $(function () {
        // 1. 测试GET接口
        $('#btnGET').on('click', function () {
          $.ajax({
            type: 'GET',
            url: 'http://127.0.0.1/api/get',
            data: { name: 'zs', age: 20 },
            success: function (res) {
              console.log(res)
            },
          })
        })
        // 2. 测试POST接口
        $('#btnPOST').on('click', function () {
          $.ajax({
            type: 'POST',
            url: 'http://127.0.0.1/api/post',
            data: { bookname: '水浒传', author: '施耐庵' },
            success: function (res) {
              console.log(res)
            },
          })
        })

        // 3. 为删除按钮绑定点击事件处理函数
        $('#btnDelete').on('click', function () {
          $.ajax({
            type: 'DELETE',
            url: 'http://127.0.0.1/api/delete',
            success: function (res) {
              console.log(res)
            },
          })
        })

        // 4. 为 JSONP 按钮绑定点击事件处理函数
        $('#btnJSONP').on('click', function () {
          $.ajax({
            type: 'GET',
            url: 'http://127.0.0.1/api/jsonp',
            dataType: 'jsonp',  // 表示要发送jsonp请求
            success: function (res) {
              console.log(res)
            },
          })
        })
      })
    </script>
  </body>
</html>

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

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

相关文章

excel查重技巧:如何用组合函数快速统计重复数据(下)

数据源照旧&#xff0c;如下图所示&#xff0c;要求统计出不重复的客户数&#xff1a;在上期我们掌握了破解公式的方法后&#xff0c;今天我们再来看看计算不重复数据个数的第二个公式套路。套路2&#xff1a;COUNT和MATCH的组合这个公式的难度就稍微有点大了&#xff0c;一起看…

Word控件Spire.Doc 【Table】教程(3):如何在C#、VB.NET中设置Word表格样式

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

聊聊帮助别人这件事--爱摸鱼的美工(12)

年近了&#xff0c;上班途中依然匆忙 看女孩子们渐渐开始倒腾 做了新发型&#xff0c;做了美美的指甲 换上了新衣服&#xff0c;买了新包 电话里讨论着 去哪里过年&#xff0c;买什么年货 好像以前的我也这样 今年挣得少了&#xff0c;不想添新衣&#xff08;不能&#xff09; …

基于QWidget和QImage的水印添加实现

目录 1. 基于QWidget的屏幕阅读水印的添加 1.1 平铺 1.1.1 核心代码 1.1.2 构造函数中设置透明度和鼠标穿透 1.1.3 调用 1.1.4 效果展示 1.2 指定位置添加水印 1.2.1 核心代码 1.2.2 设置水印透明度和鼠标穿透 1.2.3 调用 1.2.4 效果展示 2、基于QImage的屏幕水印的…

QT 学习笔记(十四)

文章目录一、TCP/IP 通信过程简介1. Socket 通信2. Linux 下的 TCP/IP 通信过程3. QT 下的 TCP/IP 通信过程3.1 在 QT 中实现 TCP/IP 服务器端通信的流程3.2 客户端通信流程二、TCP/IP 通信过程操作实现1. 服务器端2. 客户端三、服务器端和客户端实现代码1. 主函数 main.c2. 服…

重装系统重新分区方法教程

对电脑进行系统重装以后&#xff0c;若是想电脑使用起来更稳定舒适&#xff0c;就要对电脑硬盘进行系统分区&#xff0c;但是许多用户都不知道怎样分区&#xff0c;今天小编就来为大家详细介绍一下重装系统重新分区方法教程。 工具/原料&#xff1a; 系统版本&#xff1a;win1…

11 个非常实用的 Python 和 Shell 拿来就用脚本实例!

我工作中用到的几个脚本&#xff0c;主要分为&#xff1a;Python和Shell两个部分。 Python 脚本部分实例&#xff1a;企业微信告警、FTP 客户端、SSH 客户端、Saltstack 客户端、vCenter 客户端、获取域名 ssl 证书过期时间、发送今天的天气预报以及未来的天气趋势图&#xff…

Verilog语法笔记(夏宇闻第三版)-赋值语句和块语句

目录 赋值语句: (1).非阻塞(Non_Blocking)赋值方式( 如 b < a; ): (2).阻塞(Blocking)赋值方式( 如 b a; ): 例&#xff1a; 块语句&#xff1a; 顺序块&#xff1a; 例&#xff1a; 并行块&#xff1a; 例&#xff1a; ​编辑 块名&#xff1a; 起始时间和结束…

php学习笔记-php运算符,类型转换,打印输出语句相较于其他语言的特殊部分-day02

php运算符&#xff0c;类型转换&#xff0c;打印输出语句相较于其他语言的特殊部分php运算符php的类型转换php打印输出语句php运算符 1.php运算符与其他高级语言相同的部分 算术运算符&#xff08;&#xff0c;-&#xff0c;*&#xff0c;/&#xff0c;%&#xff09;&#xff0…

使用Flask快速部署PyTorch模型

对于数据科学项目来说&#xff0c;我们一直都很关注模型的训练和表现&#xff0c;但是在实际工作中如何启动和运行我们的模型是模型上线的最后一步也是最重要的工作。 今天我将通过一个简单的案例&#xff1a;部署一个PyTorch图像分类模型&#xff0c;介绍这个最重要的步骤。 …

OAK-PoE设备故障排查详解

编辑&#xff1a;OAK中国 首发&#xff1a;oakchina.cn 喜欢的话&#xff0c;请多多&#x1f44d;⭐️✍ 内容可能会不定期更新&#xff0c;官网内容都是最新的&#xff0c;请查看首发地址链接。 ▌前言 Hello&#xff0c;大家好&#xff0c;这里是OAK中国&#xff0c;我是助手…

Linux小黑板(5):磁盘与文件系统

"这月蹦迪没我" 一、浅谈磁盘 磁盘作为计算机硬件里&#xff0c;唯一的机械设备。在数据存储的领域&#xff0c;有着不可磨灭的作用。相较于&#xff0c;保持通电情况下具有保持数据的不丢失的内存&#xff0c;磁盘能够"永久性"地存储 数据。 磁盘是计算机…

1. R语言介绍、Rstudio的基本使用、【R包的安装与使用】、帮助命令、内置数据集

课程视频链接&#xff1a;https://www.bilibili.com/video/BV19x411X7C6?p1 本笔记参照该视频&#xff0c;笔记顺序做了些调整【个人感觉逻辑顺畅】&#xff0c;并删掉一些不重要的内容 系列笔记目录【持续更新】&#xff1a;https://blog.csdn.net/weixin_42214698/category_…

【Linux】进程控制:父进程与子进程

目录1 进程创建1.1 认识fork1.2 进程创建的目的1.3 写时拷贝1.4 进程创建失败的场景2 进程退出2.1 进程退出状态2.2 进程退出的方式2.3 exit、_exit、return2.3.1 概念2.3.2 区别3 进程等待3.1 理解进程等待3.2 进程等待的方式3.2.1 wait和waitpid3.2.2 status位图结构3.3 阻塞…

【一起从0开始学习人工智能0x04】python相关AI复习【超全面】【收藏】

基础小结 数据类型&#xff1a;Numbers、String、list、tuple、dict字符编码&#xff1a;可以直接.encode&#xff08;‘utf-8’&#xff09;、.decode(ascii)循环&#xff1a;for-in迭代器、whilelist列表-最频繁的数据类型。-完成大多数集合类的数据结构实现。它支持字符&am…

十六、状态管理——Vuex(4)

本章概要 表单处理Vuex 与组合 API模块 16.8 表单处理 在表单控件上通常会使用 v-model 指令进行数据绑定&#xff0c;如果绑定的数据是 Vuex 中的状态数据&#xff0c;就会遇到一些问题。看以下代码&#xff1a; form.html <div id"app"><my-component&…

一场衍生于产业的深度变革正在上演,总结起来就是产业互联网的变革

毫无疑问的是&#xff0c;一场衍生于产业的深度变革正在上演。在这样一场深度变革之中&#xff0c;曾经看似无法改变的存在&#xff0c;有了进化的可能性&#xff1b;曾经让玩家们望而却步的领域&#xff0c;有了进军的可能性。如果对这样一场深度变革进行一次总结的话&#xf…

vanishing point detection in autopilot

1. 概述 消失点一种直观的解释是图像中的平行线的交点&#xff0c;也就如下图中路面边界绘制的直线在图像中的交点。 这样的点在自动驾驶场景下可以为解析车辆状态提供一些信息&#xff0c;比如较为常规的运用便是用于车辆的pitch角度。在传统方法中会通过如霍夫算子检测图片…

2022稳定学习年度研究进展系列报告丨精华观点总结

近年来&#xff0c;在独立分布假设的前提下&#xff0c;机器学习模型的表现越来越好。但在实际应用场景中&#xff0c;数据本身却具有很强的异质性和差异性&#xff0c;这就对模型的泛化能力产生了较高的要求。为了解决分布外泛化问题&#xff0c;稳定学习应运而生。12月28日&a…

Python计算机视觉:人脸识别

讲明一下:并没有实现人脸识别的算法,只是利用人脸特征文件(文件从官网上下载),从而进行人脸识别,总感觉识别出来的效果还是有问题的,如:图片最好是人脸的正脸。 1. 人脸特征文件下载 直接去github或者gitee(建议gitee)上去搜索opencv即可,如下: 选择第一个直接进入即…