Salesforce 使用Apex調用外部數據的接口有兩種方式:SOAP 和 REST
- SOAP:Web服務使用XML格式的文件調用服務器,通常需要WSDL文檔來生成代碼
- REST:HTTP使用REST格式的文件調用服務器,推薦使用
基於WSDL的CallOut適用於SOAP方式,HTTP方式可以使用任何的HTTP Service,SOAP或者REST都可以,推薦使用REST方式. 在調用外部站點時,需要對外部站點進行授權 Setup → Remote Site Settings,
- 新建一個遠程站點
- 輸入遠程站點名稱:RESTTEST
- 輸入遠程站點URL:https://th-apex-http-callout.herokuapp.com
- 輸入站點描述信息:Salesforce REST 接口測試鏈接
- 點擊保存
REST方式調用外部接口
REST調用請求的傳輸原理如圖:
HTTP常見請求包括GET和POST請求兩種(還有DELETE和PUT等),調用服務器請求時,同時返回的還包括請求狀態碼
常見的狀態碼:
- 200 請求成功
- 404 請求找不到文件
- 500 內部服務器錯誤
POST方式獲取服務器數據示例:
// 調用一個HTTP請求 HTTP http = new HTTP(); // request 發起請求 HttpRequest request = new HttpRequest(); // 傳遞請求地址,注意將該地址添加到遠程站點列表 request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals'); // 傳遞請求方式POST request.setMethod('POST'); // 傳遞HTTP請求頭參數,編碼解析格式UTF-8 request.setHeader('Content-Type','application/json;charset=UTF-8'); // 傳遞請求參數,使用JSON串的格式 request.setBody('{"name":"mighty moose"}'); // response 響應請求 HttpResponse response = http.send(request); if(response.getStatusCode() != 201){ String str = response.getStatusCode() + ' ' + response.getStatus(); System.debug('The status code returned was not expected: ' + str); }else{ System.debug(response.getBody()); }
Tips:Callout方法在執行后續代碼的時候,會等待外部服務器的響應結果,所以Callout方法同樣可以在@future(callout=true) 中進行調用,這樣Callout方法可以在單獨的進程中調用,不會阻塞其他進程,尤其在觸發器中調用Callout方法時,必須將其包含在含有@future(callout=true) 的方法中進行
GET方式獲取服務器數據示例:
global class AnimalLocator { public static String getAnimalNameById(Integer id){ Http http = new Http(); HttpRequest request = new HttpRequest(); // 設置服務器參數 request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals/' + id); // 設置請求方式 request.setMethod('GET'); HttpResponse response = new HttpResponse(); // 發送請求 response = http.send(request); String name = ''; if(response.getStatusCode() == 200){ // 將JSON數據格式化返回 Map<String,Object> results = (Map<String,Object>)JSON.deserializeUntyped(response.getBody()); System.debug('results:' + results); Map<String,Object> animal = (Map<String,Object>)results.get('animal'); System.debug('animal:' + animal); name = (String)animal.get('name'); } return name; } }
GET請求類似直接在瀏覽器中輸入URL訪問網頁,POST請求類似用戶在頁面上提交的表單信息,相對來說POST方式傳輸數據安全性更高,GET方式更方便,可以直接在URL后面拼接參數,但是在長度上有所限制.
對於Callout測試類來說,常規的測試類在執行Callout時會報錯,所以這里需要模擬接口數據來完成測試類,一般包括StaticResourceCalloutMock和HttpCalloutMock兩種方式
使用StaticResourceCalloutMock來完成測試類,簡單說就是將接口響應的數據放在靜態資源中,然后在測試類中直接調用靜態資源中的結果作為模擬服務器響應數據.
創建一個靜態資源,名為GetAnimalLocator,格式為text/plain,輸入模擬數據如下:
創建測試類:AnimalLocatorTest
@isTest public class AnimalLocatorTest { @isTest static void testWithStaticResourceCalloutMock(){ StaticResourceCalloutMock mock = new StaticResourceCalloutMock(); // 獲取 靜態資源 GetAnimalLocator的數據 mock.setStaticResource('GetAnimalLocator'); // 模擬返回碼為200 mock.setStatusCode(200); // 模擬調用服務器Hearder參數 mock.setHeader('Content-Type', 'application/json;charset=UTF-8'); // 核心步驟,模擬服務器 Test.setMock(HttpCalloutMock.class, mock); // 調用接口 String name = AnimalLocator.getAnimalNameById(1); System.debug('name:' + name); } }
使用HttpCalloutMock方式來完成測試類,需要新增一個繼承HttpCalloutMock的Apex類,實現respond方法
@istest global class AnimalLocatorMock implements HttpCalloutMock{ global HTTPResponse respond(HTTPRequest request) { HttpResponse response = new HttpResponse(); response.setHeader('Content-Type', 'application/json'); response.setBody('{"animal":{"id":1,"name":"test name","eats":"meats","says":"good movie"}}'); response.setStatusCode(200); return response; } }
實現了HttpCalloutMock的具體類后,測試類的實現就比較簡單了
@isTest public class AnimalLocatorTest { @isTest static void testGetCalloutWithHttpCalloutMock(){ Test.setMock(HttpCalloutMock.class, new AnimalLocatorMock()); String name = AnimalLocator.getAnimalNameById(1); System.debug('name:' + name); } }
Tips:可以使用工具JSON2Apex來將json串轉換成實體類
參考數據:
