REST
ActiveMQ Classic 實作了 RESTful API 來進行訊息傳遞,這允許任何具備網路功能的裝置使用一般的 HTTP POST 或 GET 來發布或接收訊息。
如果您有興趣直接從網頁瀏覽器傳遞訊息,您可能需要查看我們的 Ajax 或 WebSockets 支援,或嘗試執行 REST 範例
REST 到 JMS 的映射
要發布訊息,請使用 HTTP POST。要接收訊息,請使用 HTTP DELETE 或 GET。
ActiveMQ Classic 有一個 Servlet 負責 HTTP 和 ActiveMQ Classic 調度器之間的整合。
注意:以下範例需要在 URL 上進行 servlet 映射。對於沒有 servlet 映射的 POST,請參閱下方的範例。
您可以將 URI 映射到 servlet,然後使用 URI 的相對部分作為主題或佇列名稱。例如,您可以 HTTP POST 到
http://www.acme.com/orders/input
這會將 HTTP POST 的內容發布到 JMS 上的 orders.input 佇列。
同樣地,您可以在上述 URL 上執行 HTTP DELETE 或 GET 從同一個佇列讀取。在這種情況下,我們會將 ActiveMQ Classic 的 MessageServlet 映射到 URI
http://www.acme.com/queue
並將其配置為接受 URI 作為佇列目的地。我們也可以做類似的事情來支援主題目的地。
我們可以使用 HTTP 會話來表示唯一的發布者或消費者。
請注意,嚴格的 REST 要求 GET 為唯讀操作;所以嚴格來說,我們不應該使用 GET 來允許使用者接收訊息。儘管我們允許這樣做,因為這簡化了 HTTP/DHTML/Ajax 的整合。
為了更清晰地將簡單的傳輸協議映射到不同的語言,您可能希望查看 Stomp。
預設設定
在 5.8 版本之前,REST API 是 Web 範例的一部分,並映射到 https://#:8161/demo/message URL。從 5.8 版本開始,API 預設在 https://#:8161/api/message URL 上可用。此外,從 5.8 版本開始,網頁伺服器預設是安全的(請參閱網頁主控台以獲取更多資訊),因此在嘗試使用時請留意這一點。以下範例將假設新的 API 位置和安全的網頁伺服器。
生產
您可以透過向伺服器發送 POST 請求來生產,例如
curl -u admin:admin -d "body=message" https://#:8161/api/message/TEST?type=queue
注意:如果沒有指定類型參數,預設會建立一個主題。若要將預設值變更為佇列,請在 webapps/demo/WEB-INF/web.xml
中使用初始化參數初始化 servlet
如下所示
<servlet>
<servlet-name>MessageServlet</servlet-name>
<servlet-class>org.apache.activemq.web.MessageServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>topic</param-name>
<param-value>false</param-value>
</init-param>
</servlet>
替代生產語法
支援一種替代的 POST 語法,使用目的地 URL 編碼參數;以下是一些範例:
# Send to queue orders.input:
curl -XPOST -d "body=message" http://admin:admin@localhost:8161/api/message?destination=queue://orders.input
# Send to topic orders.input:
curl -XPOST -d "body=message" http://admin:admin@localhost:8161/api/message?destination=topic://orders.input
訊息大小限制
預設情況下,為了防止潛在的記憶體耗盡,訊息的大小限制為 100,000
個字元。可以透過將初始化參數 maxMessageSize
設定為您選擇的值來修改此值。將值設定為 -1
會停用此限制。
若要變更該值,請修改檔案 webapps/api/WEB-INF/web.xml
,如下所示
<servlet>
<servlet-name>MessageServlet</servlet-name>
<servlet-class>org.apache.activemq.web.MessageServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
<init-param>
<param-name>maxMessageSize</param-name>
<param-value>-1</param-value>
</init-param>
</servlet>
逾時
從佇列讀取時,我們可能沒有任何訊息。我們可以使用逾時查詢參數來指示我們準備等待訊息到達的時間長度。這允許我們輪詢或封鎖直到訊息到達。
將此與 HTTP 1.1 keep-alive 套接字和管線處理相結合,我們可以透過 HTTP 有效地存取 JMS。
顯然,如果您的用戶端是 Java,那麼使用 ActiveMQ Classic 的 JMS API 是使用訊息代理的最快且最有效的方式;但是,如果您不使用 Java 或偏好 HTTP 的簡潔性,那麼它應該相當有效,特別是如果您的 HTTP 用戶端支援 keep-alive 套接字和管線處理。
接收
使用 REST API 接收訊息時,您必須在 GET 請求之間保持會話存活,否則您會為每個請求建立一個單獨的消費者,並且由於預取限制,您後續的呼叫將會掛起。
例如,您可以使用 wget
來接收訊息,如下所示
wget --user admin --password admin --save-cookies cookies.txt --load-cookies cookies.txt --keep-session-cookies https://#:8161/api/message/TEST1?type=queue
此外,如果您計畫使用 REST 擁有多個消費者,建議將預取大小設定為 1,以便所有消費者都有相同的機會獲得訊息。您可以透過將特殊參數傳遞給 MessageServlet
來做到這一點
<servlet>
<servlet-name>MessageServlet</servlet-name>
<servlet-class>org.apache.activemq.web.MessageServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>destinationOptions</param-name>
<param-value>consumer.prefetchSize=1</param-value>
</init-param>
</servlet>
在 webapps/demo/WEB-INF/web.xml
中
替代接收語法
與生產一樣,也支援一種替代的接收訊息語法,使用目的地 URL 編碼參數;以下是一些範例:
# Send to queue orders.input:
curl -XGET http://admin:admin@localhost:8161/api/message?destination=queue://orders.input
# Send to topic orders.input:
curl -XGET http://admin:admin@localhost:8161/api/message?destination=topic://orders.input
在沒有會話的情況下接收
從 5.2.0 版本開始,您可以使用 clientId
參數來避免將實際的 JMS 消費者儲存在請求會話中。使用此方法時,您不需要在請求之間保持會話存活,您只需要每次都使用相同的 clientId
。
wget --user admin --password admin https://#:8161/api/message/test?type=queue&clientId=consumerA
每個這樣的呼叫都將使用相同的 JMS 消費者,並傳遞訊息代理傳送給它的訊息。
在 5.4.1 版本中,也可以取消訂閱客戶端。方法是向伺服器發送一個具有 clientId
和 action=unsubscribe
參數的 POST 呼叫,如下所示
https://#:8161/demo/message/test?clientId=consumerA&action=unsubscribe
使用選擇器接收
從 ActiveMQ Classic 5.4.0 開始,您可以使用選擇器在使用 REST 協議接收時。若要執行此操作,只需指定帶有選擇器的適當標頭即可。若要為消費者定義選擇器,您必須在適當的 HTTP 標頭中提供它。預設情況下,選擇器標頭名稱為 selector
,因此以下範例
wget --user admin --password admin --save-cookies cookies.txt --load-cookies cookies.txt --keep-session-cookies --header="selector: test=2" https://#:8161/api/message/test?type=queue
應該只接收將 test
屬性設定為 2
的訊息。
您可以使用 WEB-INF/web.xml
中的 org.apache.activemq.selectorName
Servlet 上下文屬性來變更選擇器標頭的名稱,例如
<context-param>
<param-name>org.apache.activemq.selectorName</param-name>
<param-value>activemq-selector</param-value>
</context-param>
若要取得更多資訊,請查看 RestTest
使用一次性消費者接收
一次性接收允許 REST 呼叫接收單個訊息,然後立即關閉相關的消費者。
到目前為止的所有範例都會導致 servlet 建立並在多個 HTTP 請求中保留目的地的消費者。如果沒有注意,這些消費者很容易導致混淆,因為訊息會被調度到它們,然後因為接收 HTTP 會話或 clientId 無法連線以繼續請求訊息而保持未使用狀態。解決該問題的一種方法是使用一次性消費者。只需新增 ?oneShot=true
選項,並且一旦接收完成,就會移除該消費者;如下所示
curl -XGET http://admin:admin@localhost:8161/api/message?destination=queue://orders.input&oneShot=true
請注意,在消費者等待訊息時中斷呼叫,消費者可能會保持到伺服器使 HTTP 請求逾時,或直到訊息最終到達為止。
內容類型
預設情況下,訊息會以 text/xml
內容類型傳送給消費者。您的 REST 應用程式可能會預期 JSON 回應而不是 XML 回應。在這種情況下,您可以透過新增類似以下的內容來設定 servlet 發送回應
<servlet>
<servlet-name>MessageServlet</servlet-name>
<servlet-class>org.apache.activemq.web.MessageServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>defaultContentType</param-name>
<param-value>application/json</param-value>
</init-param>
</servlet>
到您的 WEB-INF/web.xml
。
也可以使用請求標頭覆寫預設內容類型。指定 xml=true
或 json=true
URL 參數,您將獲得具有所需內容類型的回應。
wget --user admin --password admin https://#:8161/api/message/TEST?type=queue\\&clientId=A\\&json=true
安全性
從 5.7.0 版本開始,REST API 可以連線到安全的訊息代理。該 API 使用基本驗證標頭格式來獲取使用者名稱和密碼資訊。
例如,使用 curl,您可以執行類似以下的操作
curl -u system:manager -d "body=message" https://#:8161/demo/message/TEST?type=queue
此外,您可能想要為您的連線啟用 ssl
。若要執行此操作,只需在 conf/jetty.xml
中取消註解 SecureConnector
<bean id="SecureConnector" class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
<property name="port" value="8162" />
<property name="keystore" value="file:${activemq.conf}/broker.ks" />
<property name="password" value="password" />
</bean>
REST 管理
從 5.8 版本開始,我們為訊息代理提供 REST 管理 API。使用 Jolokia JMX-HTTP 橋接器,可以使用 REST API 存取所有訊息代理度量(例如記憶體使用量)和執行管理操作(例如清除佇列)。預設情況下,管理 API 會在 https://#:8161/api/jolokia/ URL 上公開。因此,例如,您可以使用以下內容取得基本的訊息代理資料
wget --user admin --password admin --header "Origin: https://#" --auth-no-challenge https://#:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost
或更具體地說,使用以下內容取得消費者總數
wget --user admin --password admin --header "Origin: https://#" --auth-no-challenge https://#:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost/TotalConsumerCount
預設情況下,ActiveMQ Classic 使用以下 Jolokia 安全性原則
<restrict>
<!-- Enforce that an Origin/Referer header is present to prevent CSRF -->
<cors>
<strict-checking/>
</cors>
<!-- deny calling operations or getting attributes from these mbeans -->
<deny>
<mbean>
<name>com.sun.management:type=DiagnosticCommand</name>
<attribute>*</attribute>
<operation>*</operation>
</mbean>
<mbean>
<name>com.sun.management:type=HotSpotDiagnostic</name>
<attribute>*</attribute>
<operation>*</operation>
</mbean>
</deny>
</restrict>
可以透過編輯 ‘webapps/api/WEB-INF/web.xml’ 並在 ‘jolokia-agent’ servlet 下指定 ‘policyLocation’ 參數來設定自訂的 Jolokia 安全性原則。
若要取得關於 Jolokia 安全性的更多資訊,請參閱其參考手冊的安全性章節。像這樣的 API 可以輕鬆編寫針對訊息代理的監控和管理操作的腳本,另請參閱我該如何監控 ActiveMQ Classic?
注意事項和其他瑣事
- 缺少「body」參數
在上述 curl POST 範例中,「body=…」的使用至關重要。如果未在訊息本文內容前面指定此項,則網頁 servlet 會嘗試從請求中讀取本文(而不是從 -d 參數中讀取),這將導致以下例外情況
java.lang.IllegalStateException: STREAMED
at org.eclipse.jetty.server.Request.getReader(Request.java:898)
at org.apache.activemq.web.MessageServletSupport.getPostedMessageBody(MessageServletSupport.java:347)
at org.apache.activemq.web.MessageServlet.doPost(MessageServlet.java:126)
...
但是,在這種情況下的一個選項是明確指定內容類型
curl -u admin:admin -d "hello world $(date)" -H "Content-Type: text/plain" -XPOST https://#:8161/api/message?destination=queue://abc.def