RabbitMQ 消息隊列

来源:https://www.cnblogs.com/midworld/archive/2019/05/10/10847192.html
-Advertisement-
Play Games

RabbitMQ是一個在AMQP基礎上完整的,可復用的企業消息系統。他遵循Mozilla Public License開源協議。 MQ全稱為Message Queue, 消息隊列(MQ)是一種應用程式對應用程式的通信方法。應用程式通過讀寫出入隊列的消息(針對應用程式的數據)來通信,而無需專用連接來鏈 ...


RabbitMQ是一個在AMQP基礎上完整的,可復用的企業消息系統。他遵循Mozilla Public License開源協議。

MQ全稱為Message Queue, 消息隊列(MQ)是一種應用程式對應用程式的通信方法。應用程式通過讀寫出入隊列的消息(針對應用程式的數據)來通信,而無需專用連接來鏈接它們。消息傳遞指的是程式之間通過在消息中發送數據進行通信,而不是通過直接調用彼此來通信,直接調用通常是用於諸如遠程過程調用的技術。排隊指的是應用程式通過隊列來通信。隊列的使用除去了接收和發送應用程式同時執行的要求。RabbitMQ可以,多個程式同時使用RabbitMQ ,但是必須隊列名稱不一樣。採用erlang語言,屬於愛立信公司開發的。

術語(Jargon)

  • P(Producing):製造和發送信息的一方。
  • Queue:消息隊列。
  • C(Consuming):接收消息的一方。

1. 安裝

Ubuntu 上安裝

  1. 添加源、新增公鑰(不加會有警告)、更新源,安裝:rabbitmq-server
echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list

wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -

sudo apt-get update

sudo apt-get install rabbitmq-server
  1. 安裝完成後還要配置下:
# 在 rabbitmq 中添加用戶
hj@hj:~$ sudo rabbitmqctl add_user username password
Creating user "hj"      # 這為設置成功後的提示,同下

# 將用戶設置為管理員(只有管理員才能遠程登錄)
hj@hj:~$ sudo rabbitmqctl set_user_tags username administrator
Setting tags for user "hj" to [administrator]

# 為用戶設置讀寫許可權
hj@hj:~$  sudo rabbitmqctl set_permissions -p / username ".*" ".*" ".*"
Setting permissions for user "username" in vhost "/"


Windows 上安裝

  1. 安裝 pika
pip3 install -i http://pypi.douban.com/simple/ pika --trusted-host pypi.douban.com
  1. RabbitMQ 是建立在 Erlang OTP 平臺上,所有需要下載 Erlang 和 RabbitMQ,官網上下載安裝 ErlangRabbitMQ
    • Erlang:http://www.erlang.org/downloads
    • RabbitMQ:https://www.rabbitmq.com/install-windows.html
  2. 將 Erlang 添加到系統環境變數中

新建一個 ERLANG_HOME,值為 ERlang 的安裝路徑(有些安裝時會自動添加):

將 ERLANG_HOME 添加到 path 中(這裡以 win10 平臺為例,其他平臺可能會不一樣):

打開 CMD 以管理員身份證運行,輸入 erl 檢查 ERlang 是否安裝成功:

C:\Windows\system32>erl
Eshell V10.3  (abort with ^G)       # 版本
1>      # 標識符
  1. rabbitmq 需要開啟後臺管理插件 rabbitmq management

2. 隊列通信

2.1 簡單示例

下麵我們來使用 RabbitMQ 來實現一個簡單的消息收發:

  • 發送端:一臺 Windows 機器
  • 接收端:一臺 Ubuntu 虛擬機

消息不能直接發送到隊列,而是需要經過 exchange 轉發器轉發,只有與轉發器綁定了的隊列,才能收到消息。在這裡我們假設不經過 exchange 轉發:

  1. 發送端:
import pika

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.xxx', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道

# 聲明queue
channel.queue_declare(queue='hello')

# n RabbitMQ a message can never be sent directly to the queue, it always needs to go through an exchange.
# 消息不能直接發送到隊列,而是需要經過 exchange 轉發器轉發,只有與轉發器綁定了的隊列,才能收到消息
channel.basic_publish(exchange='',
                      routing_key='hello',
                      body=b'Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()

首先需要輸入上面第一章中已經註冊的 rabbitmq 賬戶,然後再連接遠程端。

其次再聲明瞭一個隊列 queue,名稱為 hello,在這裡 exchange 為空,發送的內容 body 必須是 bytes 類型。

  1. 接收端:

接收端也必須指定隊列名稱:

import pika
import time


credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道

channel.queue_declare(queue='hello')


def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    time.sleep(20)
    print(" [x] msg process done %r" % body)


channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True)


print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()

運行結果如下:

2.2 消息持久化

我們已經知道即使消費者死亡,消息(隊列)也不會丟失(在禁用 no_ack=True的前提下,現在是 auto_ack=True)

但是如果 RabbitMQ 伺服器停止,我們的任務一樣會丟失,當 RabbitMQ 退出或奔潰時,將會忘記隊列和消息,除非我們告訴它不要這樣,那麼我們就要將隊列和消息標記為持久。

  1. 確保 RabbitMQ 永遠不會丟失我們的隊列,需要設置 durable=True
# 發送端,即消息製造者
channel.queue_declare(queue='task_queue', durable=True)
  1. 將消息標記為持久性:
# 發送端,即消息製造者
properties=pika.BasicProperties(
    delivery_mode=2,  # make message persistent   使消息持久
)

設置好之後,發送端先發送一條消息,接收端先不要啟動。使用以下命令關閉啟動 rabbitmq 服務,觀察隊列和消息會不會真正丟失:

# 若命令運行失敗,可以嘗試使用 管理員模式 sudo
# 啟動rabbitmq
service rabbitmq-server start

# 停止rabbitmq 
service rabbitmq-server stop 

# 重啟rabbitmq
service rabbitmq-server restart 

# 查看當前活動的隊列 
rabbitmqctl list_queues

2.3 公平分發

所謂公平分發即一個生產者,多個消費者,類似於負載均衡。

下麵我將設置一個發送端,兩個接收端:

  1. 發送端:
import pika
import time
import sys

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道

# 聲明queue
channel.queue_declare(queue='task_queue', durable=True)


message = ' '.join(sys.argv[1:]) or "Hello World! %s" % time.time()

channel.basic_publish(exchange='',
                      routing_key='task_queue',
                      body=bytes(message, encoding='utf-8'),
                      properties=pika.BasicProperties(
                          delivery_mode=2,  # make message persistent   使消息持久
                      )

                      )
print(" [x] Sent %r" % message)
connection.close()
  1. 接收端:
import pika
import time

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道


def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)    # b'Hello World! 1557373639.5839057'
    time.sleep(20)
    print(" [x] Done")
    print("method.delivery_tag", method.delivery_tag)   # 1
    ch.basic_ack(delivery_tag=method.delivery_tag)


channel.basic_consume(on_message_callback=callback, queue='task_queue')

print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()

另外一個接收端代碼一致,在此省略,運行結果如下:

2.4 根據實際情況分發消息

事實上伺服器之間接收、處理消息的能力是不一樣的,受網路、配置等因素影響,因此公平分發消息就會導致以下問題出現:

  • 配置高、網路好的伺服器處理消息能力強、快
  • 配置一般、網路不好的伺服器有可能就會積壓很多未處理的消息

為此我們可以在接收端設置 prefetch_count=1,如果前面還有消息未處理,就告訴發送端不要給我發消息,直至處理完畢前一條消息為止:

channel.basic_qos(prefetch_count=1)     # 如果前面有消息沒處理完,就不要給我再發消息

3. 訂閱(廣播)

上面的例子基本上都是一對一發送和接收消息,如果想要將消息發送到所有隊列(queue)中,那麼就需要用到廣播了,而實現廣播的一個重要參數就是 exchange—— 消息轉發器。

exchange 在定義時是有類型的,只有符合條件的才能接收消息,大致可分為以下幾類:

  • fanout(全民廣播):凡是綁定 exchange 的隊列都可以接收到消息
  • direct(組播):以組為單位接收消息,如:發送到某個組,那麼這個組裡的所有隊列都能接收,routingKey 為關鍵字/組名
  • topic(根據特征收發消息):所有符合 routingKey 綁定的隊列都可以接收消息

3.1 fanout 方式

所有綁定 exchange 的 queue 都能接收到消息。

應用場景:視頻直播

  1. 發送端:
import pika
import sys

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道

# 指定 exchange 類型、名字
channel.exchange_declare(exchange='logs', exchange_type='fanout')

message = ' '.join(sys.argv[1:]) or "info: Hello World!"

channel.basic_publish(exchange='logs',
                      routing_key='',
                      body=bytes(message, encoding='utf-8'))

print(" [x] Sent %r" % message)
connection.close()
  1. 接收端:
import pika

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道


channel.exchange_declare(exchange='logs', exchange_type='fanout')

# 不指定queue名字, rabbit會隨機分配一個名字,exclusive=True會在使用此queue的消費者斷開後,自動將queue刪除
# 最新源代碼需要執行 queue,如果為 '',則 if empty string, the broker will create a unique queue name
            
result = channel.queue_declare('', exclusive=True)
queue_name = result.method.queue

# result = <METHOD(['channel_number=1', 'frame_type=1', "method=<Queue.DeclareOk(['consumer_count=0', 'message_count=0', 'queue=amq.gen-hRrQ-pwaT9u-32CcIokCxA'])>"])>

# queue_name = amq.gen-hRrQ-pwaT9u-32CcIokCxA


channel.queue_bind(exchange='logs', queue=queue_name)

print(' [*] Waiting for logs. To exit press CTRL+C')


def callback(ch, method, properties, body):
    print(" [x] %r" % body)


channel.basic_consume(on_message_callback=callback, queue=queue_name)

channel.start_consuming()

打開兩個終端,分別運行:

python3 fanout_send.py t1
python3 fanout_send.py t2

運行結果如下:

3.2 direct 方式

RabbitMQ 還可以根據關鍵字發送接收消息,隊列綁定關鍵字,發送端根據關鍵字發送到 exchange,exchange 再根據關鍵字判斷發給哪個隊列。

  1. 發送端:
import pika
import sys

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道

channel.exchange_declare(exchange='direct_logs', exchange_type='direct')

# python3 direct_send.py info
severity = sys.argv[1] if len(sys.argv) > 1 else 'info'  # 嚴重程度,級別, info

message = ' '.join(sys.argv[2:]) or 'Hello World!'      # Hello World!

channel.basic_publish(exchange='direct_logs',
                      routing_key=severity,
                      body=bytes(message, encoding='utf-8'))
print(" [x] Sent %r:%r" % (severity, message))  # [x] Sent 'info' : 'Hello World!'
connection.close()
  1. 接收端:
import pika
import sys

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道

channel.exchange_declare(exchange='direct_logs', exchange_type='direct')

result = channel.queue_declare('', exclusive=True)
queue_name = result.method.queue

# python3 direct_recv.py info warning error
# python3 direct_recv.py info
# python3 direct_recv.py error

severities = sys.argv[1:]       # ['direct_recv.py', 'info', 'warning', 'error']、['direct_recv.py', 'error']、['direct_recv.py', 'info']

if not severities:
    sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
    sys.exit(1)

# 迴圈綁定關鍵字
for severity in severities:
    channel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key=severity)

print(' [*] Waiting for logs. To exit press CTRL+C')


def callback(ch, method, properties, body):
    print(" [x] %r:%r" % (method.routing_key, body))


channel.basic_consume(on_message_callback=callback, queue=queue_name)

channel.start_consuming()

接收端執行打開三個終端,分別執行:

python3 direct_recv.py info warning error
python3 direct_recv.py info
python3 direct_recv.py error

然後迴圈關鍵字,綁定隊列(queue),發送端執行相應關鍵字,接收端這邊就能根據關鍵字接收消息。

運行結果如下:

3.3 topic 方式

  1. 發送端:
import pika
import sys

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道


channel.exchange_declare(exchange='topic_logs', exchange_type='topic')

routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'
message = ' '.join(sys.argv[2:]) or 'Hello World!'

channel.basic_publish(exchange='topic_logs', routing_key=routing_key, body=bytes(message, encoding='utf-8'))
print(" [x] Sent %r:%r" % (routing_key, message))
connection.close()
  1. 接收端:
import pika
import sys

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道


channel.exchange_declare(exchange='topic_logs', exchange_type='topic')

result = channel.queue_declare('', exclusive=True)
queue_name = result.method.queue

binding_keys = sys.argv[1:]
if not binding_keys:
    sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0])
    sys.exit(1)

for binding_key in binding_keys:
    channel.queue_bind(exchange='topic_logs',
                       queue=queue_name,
                       routing_key=binding_key)

print(' [*] Waiting for logs. To exit press CTRL+C')


def callback(ch, method, properties, body):
    print(" [x] %r:%r" % (method.routing_key, body))


channel.basic_consume(on_message_callback=callback, queue=queue_name)

channel.start_consuming()

接收端開啟四個終端,發送端開啟一個:

# 接收端
python3 topic_recv.py *.django.*    # 消息兩端可以是任意,中間只要是 django 即可
python3 topic_recv.py #         # 可以接收任意消息
python3 topic_recv.py mysql.*   # 以 mysql 開頭,結尾可以是任意
python3 topic_recv.py mysql.error.*     # mysql.error 開頭,結尾任意

# 發送端
python3 topic_send.py mysql.error.info
python3 topic_send.py ss.django.123
python3 topic_send.py mysql.error err happend
python3 topic_send.py python.error test

運行結果如下:

總結

  • # 號能匹配任意消息,相當於廣播
  • * 號也可以匹配任意,但是必須和其他一起使用

4. RPC(Remote Procedure Call)雙向傳輸

上面收發消息都是單向的,即一個發一個接收,接收的不能夠發送。而 RPC 是雙向的,既能夠發送也能接收。

應用場景:RPC 服務功能

  1. 發送端:
import pika
import uuid


class FibonacciRpcClient(object):
    def __init__(self):

        credentials = pika.PlainCredentials('username', 'password')
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(
            '192.168.21.128', credentials=credentials))

        channel = self.connection.channel()  # 建立 rabbit 協議通道

        self.channel = self.connection.channel()

        result = self.channel.queue_declare('', exclusive=True)
        self.callback_queue = result.method.queue

        self.channel.basic_consume(on_message_callback=self.on_response,
                                   queue=self.callback_queue,
                                   auto_ack=True)  #準備接受命令結果

    def on_response(self, ch, method, props, body):
        """"callback方法"""
        if self.corr_id == props.correlation_id:
            self.response = body

    def call(self, n):
        self.response = None
        self.corr_id = str(uuid.uuid4()) #唯一標識符
        self.channel.basic_publish(exchange='',
                                   routing_key='rpc_queue',
                                   properties=pika.BasicProperties(
                                       reply_to=self.callback_queue,
                                       correlation_id=self.corr_id,
                                   ),
                                   body=str(n))

        count = 0
        while self.response is None:
            self.connection.process_data_events() #檢查隊列里有沒有新消息,但不會阻塞
            count += 1
            print("check...", count)

        return int(self.response)


fibonacci_rpc = FibonacciRpcClient()

print(" [x] Requesting fib(30)")
response = fibonacci_rpc.call(5)
print(" [.] Got %r" % response)
  1. 接收端:
import pika
import time

credentials = pika.PlainCredentials('username', 'password')
connection = pika.BlockingConnection(pika.ConnectionParameters(
    '192.168.21.128', credentials=credentials))

channel = connection.channel()      # 建立 rabbit 協議通道

channel.queue_declare(queue='rpc_queue')


def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)


def on_request(ch, method, props, body):
    n = int(body)

    print(" [.] fib(%s)" % n)
    response = fib(n)

    ch.basic_publish(exchange='',
                     routing_key=props.reply_to,
                     properties=pika.BasicProperties(correlation_id=props.correlation_id),
                     body=str(response))
    ch.basic_ack(delivery_tag=method.delivery_tag)


channel.basic_qos(prefetch_count=1)
channel.basic_consume(on_message_callback=on_request, queue='rpc_queue')

print(" [x] Awaiting RPC requests")
channel.start_consuming()

運行結果如下:

5. 參考:

6. 常用命令

#創建用戶
rabbitmqctl add_user rabbitadmin 123456
rabbitmqctl set_user_tags rabbitadmin administrator

# 給用戶授權
rabbitmqctl set_permissions -p / rabbitadmin ".*" ".*" ".*"

# 開啟插件管理頁面
rabbitmq-plugins enable rabbitmq_management

rabbitmq-server start   # 啟動服務
rabbitmq-server stop     # 關閉服務
rabbitmq-server restart  # 重啟服務
rabbitmq-server status  # 查看服務狀態

ps -ef|grep rabbitmq    # 查看埠
rabbitmqctl list_queues     # 查看隊列消息
./rabbitmqctl list_users    #   查看用戶列表命令
rabbitmqctl  delete_user  Username      # 刪除用戶命令
whereis rabbitmq    #查看rabbitmq安裝目錄

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在c語言中實現全排列,對於剛接觸c語言,還沒學習演算法的人來說,比較困難了吧。估計大佬也不會看這種基礎的東西,全排列實現的辦法很多,在c++中有一個專門的函數可以使用,但是在c中實現就有點困難了。如果你想出用一個迴圈使一個數字每一位都不相同,那麼你就走進了死衚衕,這種辦法運算量巨大,往往到了高位就會超 ...
  • 轉自:PHP在無限分類時註意的一些問題(http://lxiaoke.cn) (註意:代碼使用的是原生PHP,旨在提供解決思路)1 無限分類的查找(獲取所有節點) 代碼: /** * 無限分類查詢,預設 pid 為 0 * @param $pid * @return array $res */ pr ...
  • JAVA流程語句有幾下幾種: 一、if語句: 1.if語句:如果滿足條件語句,則執行執行語句; if(條件語句){ 執行語句; ....; } 2.if....else語句:如果滿足判斷語句,則執行執行語句1,否則執行執行語句2; if(判斷語句{ 執行語句1; .....; }else{ 執行語句 ...
  • 大家好,忙裡抽空更新一下自己的博客,算是自己的一個進步,C語言視頻啟蒙我早就看完啦,只是覺得這個視頻真不錯,所以給大家分享一下,同時自己還有很多沒有理解透徹,寫寫博客算是一個筆記更是對自己所學的知識的吸收,廢話不多直接開始今天的主題,"C語言的選擇結構" 關係運算符 小於:< 大於:> 等於:= = ...
  • 描述Object wait()/notify()跟Condition await()/signal()的基本用法,三連問:解釋為什麼wait() 要放在while裡面?為什麼wait()方法放在Object對象中?為什麼wait()必須在同步方法/代碼塊中調用?以及這兩種通知/等待機制的區別 ...
  • 昨天組內同學在使用php父子進程模式的時候遇到了一個比較詭異的問題 簡單說來就是:因為fork,父子進程共用了一個redis連接、然後父子進程在發送了各自的redis請求分別獲取到了對方的響應體。 復現示例代碼: testFork.php PowerSpawn.php 主要用戶進程fork管理工作 ...
  • 1. HTML 定義 BS 模式:Browser、Server,即瀏覽器與伺服器模式。 HTML(Htyper Markup Language)即超文本標記語言,超文本(頁面內可以包含圖片、鏈接、引用、甚至程式 ),標記語言:標記(標簽)構成的語言。 網頁 網頁即 HTML文檔,由瀏覽器解析並展示出 ...
  • 學習PyQuery庫 好了,又是學習的時光啦,今天學習pyquery 來進行網頁解析 常規導入模塊(PyQuery庫中的pyquery類) from pyquery import PyQuery as pq 通常使用url初始化 doc = pq(url='http://www.baidu.com' ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...