RabbitMQ 全面解析:语法与其他消息中间件的对比分析
1. 引言
在分布式系统和微服务架构中,消息中间件扮演着重要的角色。它们能够解耦服务、平衡负载、提高系统的可扩展性和可靠性。RabbitMQ 是其中广受欢迎的一种。本文将从 RabbitMQ 的基础概念、语法介绍、以及与其他消息中间件的对比角度,全面剖析其在实际项目中的应用及优劣势。
2. RabbitMQ 简介
RabbitMQ 是基于 AMQP(Advanced Message Queuing Protocol)协议的开源消息代理,由 Pivotal Software 开发。其核心功能包括消息的接收、存储和分发,支持复杂的消息路由,是企业级应用中的重要组成部分。
2.1 RabbitMQ 的主要特点
- 可靠性:支持持久化、消息确认和发布确认机制,确保消息不会丢失。
- 灵活的路由:通过交换器(Exchange)实现多种路由策略,如直连(Direct)、主题(Topic)、扇出(Fanout)和头交换(Headers)。
- 支持多种协议:不仅支持 AMQP,还支持 MQTT、STOMP 和 HTTP 等协议。
- 管理与监控:提供丰富的管理插件和 Web 管理控制台,可以实时监控消息流、队列和连接。
- 横向扩展:支持集群和高可用性配置。
3. RabbitMQ 基本语法与使用
3.1 RabbitMQ 的核心概念
在理解 RabbitMQ 语法和使用之前,需熟悉一些核心概念:
- Producer(生产者):发送消息的应用程序。
- Queue(队列):存储消息的缓存区。
- Consumer(消费者):接收并处理消息的应用程序。
- Exchange(交换器):决定消息如何路由到特定队列。
- Binding(绑定):交换器和队列之间的连接。
3.2 基本使用与语法示例
生产者代码示例:
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;public class Producer {private final static String QUEUE_NAME = "hello";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, true, false, false, null);String message = "Hello, RabbitMQ!";channel.basicPublish("", QUEUE_NAME, null, message.getBytes());System.out.println(" [x] Sent '" + message + "'");}}
}
消费者代码示例:
import com.rabbitmq.client.*;public class Consumer {private final static String QUEUE_NAME = "hello";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");Connection connection = factory.newConnection();Channel channel = connection.createChannel();channel.queueDeclare(QUEUE_NAME, true, false, false, null);DeliverCallback deliverCallback = (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + message + "'");};channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});}
}
3.3 参数详细说明
- queueDeclare() 方法:
- queue:队列名称。
- durable:是否持久化,
true
表示队列在服务器重启后仍存在。 - exclusive:是否仅限于当前连接使用。
- autoDelete:当消费者断开连接时是否自动删除队列。
- arguments:队列的其他可选参数。
- basicPublish() 方法:
- exchange:交换器名称。
- routingKey:用于将消息路由到队列的路由键。
- props:消息的其他属性,如持久性、优先级等。
- body:消息内容。
3.4 死信队列(DLQ)
在消息队列系统中,死信队列(Dead Letter Queue, DLQ) 是一种特殊的队列,用于存储无法被正常处理的消息。消息在被拒绝、过期或达到最大重试次数后,都会被转移到死信队列中,以便后续分析和处理。
3.4.1 死信队列的适用场景
- 消息拒绝(Rejection without requeue):消费者在处理消息时使用
basicReject
或basicNack
拒绝消息,并且不将消息重新放回队列。 - 消息过期(TTL 到期):消息在队列中超过其设置的生存时间(TTL)而未被消费。
- 队列长度限制:队列达到其最大长度时,新的消息会被转移到死信队列。
3.4.2 配置死信队列的参数
在 RabbitMQ 中,要使用死信队列,需要在声明队列时配置相关参数:
x-dead-letter-exchange
:指定死信消息要发送到的交换器。x-dead-letter-routing-key
:指定死信消息的路由键(可选)。
示例配置:
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "dlx_exchange");
args.put("x-dead-letter-routing-key", "dlx_routing_key");channel.queueDeclare("main_queue", true, false, false, args);
channel.exchangeDeclare("dlx_exchange", "direct");
channel.queueDeclare("dead_letter_queue", true, false, false, null);
channel.queueBind("dead_letter_queue", "dlx_exchange", "dlx_routing_key");
3.4.3 死信队列的应用场景
- 重试机制:使用死信队列来捕获处理失败的消息,触发后续的重试逻辑或报警系统。
- 监控与告警:定期检查死信队列,检测和解决系统中的异常情况。
- 消息持久化分析:将处理失败的消息持久化存储,便于后续数据分析和错误修复。
3.4.4 示例:处理死信队列中的消息
DeliverCallback deliverCallback = (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received dead letter message: '" + message + "'");// 实现死信消息的处理逻辑
};
channel.basicConsume("dead_letter_queue", true, deliverCallback, consumerTag -> {});
3.4.5 实践中的注意事项
- 设置合理的 TTL 和重试策略:避免消息过早进入死信队列,增加不必要的复杂性。
- 监控死信队列的大小:确保死信队列不会在短时间内积压大量消息,影响系统性能。
- 分析死信原因:通过死信消息的属性(如
headers
)和日志,找出导致消息失败的原因。
配置和使用死信队列可以有效提升系统的可靠性和可维护性,帮助开发者快速定位问题并采取相应措施。
4. RabbitMQ 与其他消息中间件的对比
4.1 RabbitMQ vs. Kafka
RabbitMQ 和 Kafka 是两种截然不同的消息中间件,各自有其优缺点。
特性 | RabbitMQ | Kafka |
---|---|---|
协议 | AMQP | 自定义协议(Kafka Protocol) |
消息模型 | 面向消息队列,提供消息确认机制 | 面向日志,消息存储在分区 |
持久化 | 支持持久化,持久化机制较为成熟 | 默认持久化,优化了日志存储 |
性能 | 每秒万级消息传递,延迟低 | 支持百万级消息传递,适合高吞吐场景 |
消费模式 | 点对点和发布/订阅 | 发布/订阅,支持消息重放 |
用途 | 企业消息队列、任务分发 | 日志处理、数据流分析 |
优缺点分析:
- RabbitMQ 优点:支持多种协议、灵活的路由、可靠的消息确认。
- RabbitMQ 缺点:在高吞吐量场景下性能受限。
- Kafka 优点:高吞吐、分布式存储、适合大规模数据流处理。
- Kafka 缺点:消息投递延迟较高,不适合低延迟场景。
4.2 RabbitMQ vs. ActiveMQ
特性 | RabbitMQ | ActiveMQ |
---|---|---|
协议 | AMQP | JMS、AMQP、MQTT 等多种协议支持 |
管理界面 | 丰富的 Web 界面管理和监控 | Web Console 界面较简单 |
持久化 | 支持持久化策略,消息持久化 | 持久化较为复杂,可扩展性较差 |
性能 | 中等,适合中型应用 | 较低,适合轻量级应用 |
社区支持 | 活跃,广泛使用 | 较小,但依赖于 Apache 背书 |
总结:RabbitMQ 在复杂消息路由和协议支持方面有优势,而 ActiveMQ 在协议兼容性和简单应用中更容易上手。
4.3 RabbitMQ vs. Redis Pub/Sub
特性 | RabbitMQ | Redis Pub/Sub |
---|---|---|
消息确认 | 支持 | 不支持 |
持久化 | 支持 | 仅在 Redis 数据库持久化时间接支持 |
性能 | 中等,提供可靠消息传递 | 极高,但无消息持久化 |
用途 | 复杂消息队列、企业级应用 | 实时推送消息,短时间任务传递 |
总结:Redis Pub/Sub 适合实时和短时间的消息广播,RabbitMQ 则更适合需要消息持久化和确认的场景。
5. 在实际项目中的应用及优化
5.1 如何选择消息中间件
在选择消息中间件时,需要考虑以下因素:
- 消息持久化与确认:如需要可靠性高的消息传递,RabbitMQ 是更好的选择。
- 吞吐量要求:对于高吞吐量的日志处理和数据流,Kafka 更为适合。
- 协议支持:如需支持多种协议,RabbitMQ 或 ActiveMQ 是不错的选择。
5.2 RabbitMQ 的优化实践
为了在高并发、高可靠性场景中充分发挥 RabbitMQ 的优势,需要对其进行优化配置和调整。以下是一些常见的优化实践:
5.2.1 持久化与确认机制
在企业级应用中,为了防止消息丢失,应启用消息的持久化和消费者确认机制。
-
消息持久化: 消息持久化是为了确保在 RabbitMQ 服务器重启或宕机时,消息不会丢失。实现消息持久化的方法是在声明队列时设置
durable
参数为true
,并在发送消息时指定MessageProperties.PERSISTENT_TEXT_PLAIN
属性。示例:
// 声明持久化队列 channel.queueDeclare("durable_queue", true, false, false, null);// 发布持久化消息 channel.basicPublish("", "durable_queue", MessageProperties.PERSISTENT_TEXT_PLAIN, "Persistent Message".getBytes());
-
消费者确认: 启用消费者确认可以保证消息被成功处理后才会从队列中删除。RabbitMQ 支持
basicAck
、basicNack
和basicReject
等确认模式。示例:
DeliverCallback deliverCallback = (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + message + "'");// 手动确认消息channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); };channel.basicConsume("durable_queue", false, deliverCallback, consumerTag -> {});
优化提示:
- 设置
autoAck
为false
,以手动确认消息,确保消费者在消息处理失败时不会丢失消息。 - 配置发布确认(Publisher Confirms)模式,确保生产者能够接收消息被 RabbitMQ 正确接收的确认。
- 设置
5.2.2 并发与负载均衡
实现高并发和负载均衡可以通过横向扩展 RabbitMQ 集群来完成。
-
集群模式: 在 RabbitMQ 中,通过集群模式实现节点间的负载均衡和高可用性。典型的集群模式包括:
- 普通集群:所有节点共享队列元数据,但消息内容不共享。
- 镜像队列:将消息复制到集群中的多个节点上,提供高可用性保障。
集群部署示例:
# 在每个节点上初始化集群 rabbitmqctl stop_app rabbitmqctl join_cluster rabbit@<master_node> rabbitmqctl start_app
优化提示:
-
使用 HAProxy 或 负载均衡器 来分发请求到集群中不同的节点,避免单节点过载。
-
配置
镜像队列策略 :
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
-
消费者并发: RabbitMQ 支持多个消费者并发处理消息。通过增加
basicQos
中的prefetchCount
来控制每个消费者可以处理的未确认消息数,从而实现负载均衡。示例:
channel.basicQos(10); // 每个消费者最多处理 10 条未确认的消息
5.2.3 队列分区与限流
为了防止队列过载,可以使用 x-max-length
和 x-max-length-bytes
来限制队列的最大消息数量或总字节大小。
-
配置队列的最大长度:
x-max-length
参数设置队列的最大消息数。当队列中的消息数量超过此值时,最早的消息将被丢弃。示例:
Map<String, Object> args = new HashMap<>(); args.put("x-max-length", 1000); // 队列最多存储 1000 条消息 channel.queueDeclare("limited_queue", true, false, false, args);
-
配置队列的最大字节长度:
x-max-length-bytes
参数设置队列的最大字节数限制,当超过此限制时,最早的消息将被丢弃。示例:
Map<String, Object> args = new HashMap<>(); args.put("x-max-length-bytes", 10485760); // 队列最多存储 10 MB 的消息 channel.queueDeclare("byte_limited_queue", true, false, false, args);
优化提示:
- 设置合理的限流参数,防止队列长时间积压导致内存或磁盘过载。
- 定期清理不再需要的消息队列或调整队列策略,确保系统资源的有效利用。
通过以上优化实践,RabbitMQ 可以在各种复杂的企业级应用中提供稳定、高效的消息服务。
相关文章:
RabbitMQ 全面解析:语法与其他消息中间件的对比分析
1. 引言 在分布式系统和微服务架构中,消息中间件扮演着重要的角色。它们能够解耦服务、平衡负载、提高系统的可扩展性和可靠性。RabbitMQ 是其中广受欢迎的一种。本文将从 RabbitMQ 的基础概念、语法介绍、以及与其他消息中间件的对比角度,全面剖析其在…...
Three.js 搭建3D隧道监测
Three.js 搭建3D隧道监测 Three.js 基础元素场景scene相机carema网络模型Mesh光源light渲染器renderer控制器controls 实现3d隧道监测基础实现道路实现隧道实现多个摄像头点击模型进行属性操作实现点击模型发光效果 性能监视器stats引入使用 总结完整代码 我们将通过three.js技…...
「IDE」集成开发环境专栏目录大纲
✨博客主页何曾参静谧的博客📌文章专栏「IDE」集成开发环境📚全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定…...
MySQL-初识数据库
目录 一、数据库基础概念 1、SQL 2、数据(Data) 3、数据库(DB) 4、数据库管理系统DBMS 5、数据库系统DBS 6、关系模型(Relational Model) 7、E-R图 8、常见的数据库 9、数据库基本操作 一、数据库…...
初始 html
html 文件结构 html 标签是整个 html 文件的根标签(最顶层标签) head 标签中写页面的属性. body 标签中写的是页面上显示的内容 title 标签中写的是页面的标题 <html><head><title>这是一个标题</title></head><body></body> <…...
前端 call、bind、apply的实际使用
目录 一、call 1、继承的子类可以使用父类的方法 2、可以接收任意参数 二、call、apply、bind比较 1、案例一 2、案例二 三、总结 这个三个方法都是改变函数的this指向的方法。 一、call 代码: const obj{uname:"pink"}function fn(){console.log…...
非关系型数据库NoSQL的类型与优缺点对比
NoSQL数据库根据数据模型和应用场景主要分为四种类型:键值型、列族型、文档型和图形型。以下是对每种类型的详细描述,包括其应用场景、优缺点的比较: 1. 键值型数据库 (Key-Value Store) 典型代表 RedisMemcachedAmazon DynamoDB 应用场景…...
面试击穿mysql
Mysql三大范式: 第一范式(1NF): 不符合第一范式的典型情况是在一个字段中存放多种不同类型的详细信息。例如,在商品表中,若将商品名称、价格和类型都存储在同一个字段中,会带来诸多弊端。首先,在…...
PyQt5超详细教程终篇
PyQt5超详细教程 前言 接: [【Python篇】PyQt5 超详细教程——由入门到精通(序篇)](【Python篇】PyQt5 超详细教程——由入门到精通(序篇)-CSDN博客) 建议把代码复制到pycahrm等IDE上面看实际效果,方便理…...
Android OpenGL ES详解——纹理:纹理过滤GL_NEAREST和GL_LINEAR的区别
目录 一、概念 1、纹理过滤 2、邻近过滤 3、线性过滤 二、邻近过滤和线性过滤的区别 三、源码下载 一、概念 1、纹理过滤 当纹理被应用到三维物体上时,随着物体表面的形状和相机视角的变化,会导致纹理在渲染过程中出现一些问题,如锯齿…...
Elasticsearch实战应用:从入门到精通
在当今这个数据爆炸的时代,如何快速、有效地从海量数据中检索信息,已经成为了许多企业和开发者面临的挑战。Elasticsearch,作为一个基于Lucene的搜索引擎,以其强大的全文搜索能力、分布式特性以及易用性,成为了解决这一…...
axios平替!用浏览器自带的fetch处理AJAX(兼容表单/JSON/文件上传)
fetch 是啥? fetch 函数是 JavaScript 中用于发送网络请求的内置 API,可以替代传统的 XMLHttpRequest。它可以发送 HTTP 请求(如 GET、POST 等),并返回一个 Promise,从而简化异步操作 基本用法 /* 下面是…...
【优选算法 — 滑动窗口】水果成篮 找到字符串中所有字母异位词
水果成篮 水果成篮 题目描述 因为只有两个篮子,每个篮子装的水果种类相同,如果从 0 开始摘,则只能摘 0 和 1 两个种类 ; 因为当我们在两个果篮都装有水果的情况下,如果再走到下一颗果树,果树的水果种类…...
Go 数据库查询与结构体映射
下面是关于如何使用 Go 进行数据库查询并映射数据到结构体的教程,重点讲解 结构体字段导出 和 db 标签 的使用。 Go 数据库查询与结构体映射教程 在 Go 中,我们可以使用 database/sql 或 sqlx 等库与数据库进行交互。为了方便地将数据库查询结果映射到结…...
Wi-Fi背后的工作原理与技术发展历程介绍【无线通信小百科】
1个视频说清楚WIFI:频段/历程/技术参数/常用模块 智能手机拥有率越来越高的今天,大家已经习惯了通过无线网络上网的方式。除了在外面需要用手机流量,我们通常在家里或者机场,商场都可以通过Wi-Fi连接上网。本期文章将为大家介绍Wi…...
2024 年(第 7 届)“泰迪杯”数据分析技能赛B 题 特殊医学用途配方食品数据分析 完整代码 结果 可视化分享
一、背景特殊医学用途配方食品简称特医食品,是指为满足进食受限、消化吸收障碍、代谢素乱或者特定疾病状态人群对营养素或者膳食的特殊需要,专门加工配置而成的配方食品,包括0月龄至12月龄的特殊医学用途婴儿配方食品和适用于1岁以上的特殊医…...
STM32学习笔记------编程驱动蜂鸣器实现音乐播放
1. 硬件准备 STM32开发板:STM32F407系列蜂鸣器:常见的蜂鸣器分为两类:有源蜂鸣器和无源蜂鸣器。若使用有源蜂鸣器,只需提供电源和控制信号即可;若使用无源蜂鸣器,则需要控制频率。外接电源(可选…...
ubuntu18.04 安装与卸载NCCL conda环境安装PaddlePaddle
cuda版本11.2 说明PaddlePaddle需要安装NCCL 1、Log in | NVIDIA Developer 登录官网 找到对应版本 官方提供了多种安装方式,本文使用Local installers (x86)本地安装 点击对应的版本下载如: nccl-local-repo-ubuntu1804-2.8.4-cuda11.2_1.0-1_amd6…...
AI有鼻子了,还能远程传输气味,图像生成香水
众所周知,图像、音乐能用AI生成,但出乎意料的是,气味也行。最近,一个名叫Osmo的初创公司宣布,他们成功地将气味数字化了。第一个成功的案例是“新鲜的夏季李子”,而且复现出的味道“闻起来”很不错。整个过…...
学习配置dify过程记录
最近在学习安装 Dify 并集成 Ollama 和 Xinference,学习过程中遇到很多问题,所以我都记录下来。 本人电脑环境:MacBook Pro 15.1系统 基本是基于B站教程一步步搭建: 【Dify快速入门 | 本地部署Dify基于Llama 3.1和OpenAI创建聊天机器人与知…...
简易抽奖器源码以及打包操作
import wx import random import time# 定义Myframe类,继承Frame class Myframe(wx.Frame):# 奖品rewards [桥本香奈, 二代CC, NaNa, 情深叉]# 构造方法def __init__(self):# 父类初始化super().__init__(None, title主界面, size(500, 400), pos(500, 200))# 创建面板&#x…...
一文了解什么是腾讯云开发
一文了解什么是腾讯云开发 关于云开发的猜想腾讯云开发腾讯云开发的优势无服务跨平台轻松托管节约成本 快速上手云开发环境快速搭建管理后台 云开发体验 关于云开发的猜想 说到云开发,作为开发者的大家是否大概就有了想法。比如说过去的开发工作都是在自己本地电脑…...
[CKS] K8S NetworkPolicy Set Up
最近准备花一周的时间准备CKS考试,在准备考试中发现有一个题目关于不安全项目修复的题目。 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] K8S Ne…...
【JAVA】Java基础—面向对象编程:构造方法-实现一个Car类,包含多个构造方法,创建不同的汽车对象
在Java中,构造方法则是用于创建对象的特殊方法。通过构造方法,可以在创建对象时初始化其属性。构造方法的重载允许我们根据不同的需求定义多个构造方法,从而灵活地创建对象。 我们可以将汽车的构造方法比作汽车的配置选项。比如,…...
初识网络编程TCP/IP
目录 前言相关名词解释应用层协议——HTTP传输层协议socketTCP帧头格式三次握手、四次挥手 UDPTCP的socket实现 参考博文 前言 刚碰到网络编程,会出现一堆协议、概念、这层次那技术的,头都大了,还是得总结总结…… 相关名词解释 ✨✨网络…...
快速入门Zookeeper
Zookeeper ZooKeeper作为一个强大的开源分布式协调服务,扮演着分布式系统中至关重要的角色。它提供了一个中心化的服务,用于维护配置信息、命名、提供分布式同步以及提供组服务等。通过其高性能和可靠的特性,ZooKeeper能够确保在复杂的分布式…...
Filter and Search 筛选和搜索
Goto Data Grid 数据网格 Filter and Search 筛选和搜索 Filter Drop-down Menus (Excel-style) 筛选器下拉菜单(Excel 样式) 要调用列的筛选器下拉菜单,请单击列标题中的筛选器图标。在 “Values” 选项卡中,用户可以从 Data …...
spark的学习-06
SparkSQL读写数据的方式 1)输入Source 方式一:给定读取数据源的类型和地址 spark.read.format("json").load(path) spark.read.format("csv").load(path) spark.read.format("parquet").load(path) 方式二:…...
Linux C/C++ Socket 编程
本文目录 Linux C语言 socket 编程 client 端头文件 unistd.h & arpa/inet.h1. **unistd.h**2. **arpa/inet.h** socket() 创建套接字sockaddr_in 结构体inet_pton()connect()send()recv()send() 和 recv() 中的 flags 参数**默认行为(flags 0)的特…...
Flutter错误: uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared
前言 今天要做蓝牙通信的功能,我使用了flutter_reactive_ble这个库,但是在运行的时候发现一下错误 Launching lib/main.dart on AQM AL10 in debug mode... /Users/macbook/Desktop/test/flutter/my_app/android/app/src/debug/AndroidManifest.xml Err…...
做网站的学校有哪些/标题关键词优化报价
2019独角兽企业重金招聘Python工程师标准>>> 负载均衡 负载均衡是一种手段,用来把对某种资源的访问分摊给不同的设备,从而减轻单点的压力。 架构图 图中左侧为ZooKeeper集群,右侧上方为工作服务器,下面为客户端。每台工…...
兰州400电话网站建设/企点客服
2019独角兽企业重金招聘Python工程师标准>>> 上次关于的这个问题的处理一般是没有问题,但是如果对于重复调用datagrid的selectRow和clearSelections事件,会造成颜色的混乱,因为在每次调用onSelect函数的时候,都首先会调用 onUnselectAll函数,而且调用clearSelection…...
八宝山做网站公司/百度收录接口
大工程的仿真往往需要比较长的时间,仿真时直接查看信号有时却忘了添加。而保存波形文件能在仿真完成后查看波形,为之后的分析提供方便。 在仿真的tb文件中加入 initialbegin$dumpfile("mydumpfile.vcd");$dumpvars ;end 于是生成vcd文件&#…...
web网页是什么/广东seo推广贵不贵
介绍JwtToken认证之前,必须要掌握.Net Core认证系统的核心原理,如果你还不了解,请参考.Net Core 认证组件源码解析,且必须对jwt有基本的了解,如果不知道,请百度.最重要的是你还需要掌握identity server4的基本用法,关于identity server4因为涉及到两个协议Oath2.0和openid conn…...
安阳企业建网站/营销策划推广
实验环境:IP地址描述192.168.5.181CentOS7系统,base源安装好了mariadb,作为ftp服务端,作为认证服务端192.168.5.121CentOS6系统,作为ftp客户端认证模块pam_mysql.so的安装需要从网上下载pam_mysql.so的源码包,pam_mysq…...
网站seo怎么做/整合营销传播的明显特征是
以往的开发方式:小程序必须要绑定至少一个合法安全域名,且该域名必须是使用ssl证书的,也就是要以https协议。小程序正式上线后,只能跟合法安全域名内的域名进行信息互通。如果请求没有配置过的域名,会被微信屏蔽。而对…...