操作方法:使用 HTTP 调用服务

使用 servcie invocation 在服务之间调用

本文介绍如何使用唯一的应用程序 ID 部署每个服务,以便其他服务可以使用服务调用 API 发现和调用这些端点。

Diagram showing service invocation of example service

注意

如果你还没有,请尝试使用服务调用快速入门快速了解如何使用服务调用 API。

为您的服务选择一个ID

Dapr 允许您为您的应用分配一个全局唯一ID。 此 ID 为您的应用程序封装了状态,不管它可能有多少实例。

  1. dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- python3 checkout/app.py
  2. dapr run --app-id order-processor --app-port 8001 --app-protocol http --dapr-http-port 3501 -- python3 order-processor/app.py

如果您的应用程序使用TLS,您可以通过设置 --app-protocol https,告诉Dapr通过TLS连接调用您的应用程序。

  1. dapr run --app-id checkout --app-protocol https --dapr-http-port 3500 -- python3 checkout/app.py
  2. dapr run --app-id order-processor --app-port 8001 --app-protocol https --dapr-http-port 3501 -- python3 order-processor/app.py
  1. dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- npm start
  2. dapr run --app-id order-processor --app-port 5001 --app-protocol http --dapr-http-port 3501 -- npm start

如果您的应用程序使用TLS,您可以通过设置 --app-protocol https,告诉Dapr通过TLS连接调用您的应用程序。

  1. dapr run --app-id checkout --dapr-http-port 3500 --app-protocol https -- npm start
  2. dapr run --app-id order-processor --app-port 5001 --dapr-http-port 3501 --app-protocol https -- npm start
  1. dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- dotnet run
  2. dapr run --app-id order-processor --app-port 7001 --app-protocol http --dapr-http-port 3501 -- dotnet run

如果您的应用程序使用TLS,您可以通过设置 --app-protocol https,告诉Dapr通过TLS连接调用您的应用程序。

  1. dapr run --app-id checkout --dapr-http-port 3500 --app-protocol https -- dotnet run
  2. dapr run --app-id order-processor --app-port 7001 --dapr-http-port 3501 --app-protocol https -- dotnet run
  1. dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- java -jar target/CheckoutService-0.0.1-SNAPSHOT.jar
  2. dapr run --app-id order-processor --app-port 9001 --app-protocol http --dapr-http-port 3501 -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar

如果您的应用程序使用TLS,您可以通过设置 --app-protocol https,告诉Dapr通过TLS连接调用您的应用程序。

  1. dapr run --app-id checkout --dapr-http-port 3500 --app-protocol https -- java -jar target/CheckoutService-0.0.1-SNAPSHOT.jar
  2. dapr run --app-id order-processor --app-port 9001 --dapr-http-port 3501 --app-protocol https -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar
  1. dapr run --app-id checkout --dapr-http-port 3500 -- go run .
  2. dapr run --app-id order-processor --app-port 6006 --app-protocol http --dapr-http-port 3501 -- go run .

如果您的应用程序使用TLS,您可以通过设置 --app-protocol https,告诉Dapr通过TLS连接调用您的应用程序。

  1. dapr run --app-id checkout --dapr-http-port 3500 --app-protocol https -- go run .
  2. dapr run --app-id order-processor --app-port 6006 --dapr-http-port 3501 --app-protocol https -- go run .

在部署到 Kubernetes 时设置一个应用程序的 ID

在 Kubernetes 中,在您的pod上设置dapr.io/app-id注解:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: <language>-app
  5. namespace: default
  6. labels:
  7. app: <language>-app
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. app: <language>-app
  13. template:
  14. metadata:
  15. labels:
  16. app: <language>-app
  17. annotations:
  18. dapr.io/enabled: "true"
  19. dapr.io/app-id: "order-processor"
  20. dapr.io/app-port: "6001"
  21. ...

如果您的应用程序使用TLS连接,您可以使用app-protocol: "https"注解告知Dapr通过TLS调用您的应用程序(完整列表在这里)。 请注意,Dapr 不会验证应用程序提供的 TLS 证书。

调用服务

要使用 Dapr 调用应用程序,您可以在任意 Dapr 实例中使用 invoke API。 Sidecar 编程模型鼓励每个应用程序与自己的 Dapr 实例交互。 Dapr sidecar 之间相互发现并进行通信。

下面是利用 Dapr SDK 进行服务调用的代码示例。

  1. #dependencies
  2. import random
  3. from time import sleep
  4. import logging
  5. import requests
  6. #code
  7. logging.basicConfig(level = logging.INFO)
  8. while True:
  9. sleep(random.randrange(50, 5000) / 1000)
  10. orderId = random.randint(1, 1000)
  11. #Invoke a service
  12. result = requests.post(
  13. url='%s/orders' % (base_url),
  14. data=json.dumps(order),
  15. headers=headers
  16. )
  17. logging.basicConfig(level = logging.INFO)
  18. logging.info('Order requested: ' + str(orderId))
  19. logging.info('Result: ' + str(result))
  1. //dependencies
  2. import axios from "axios";
  3. //code
  4. const daprHost = "127.0.0.1";
  5. var main = function() {
  6. for(var i=0;i<10;i++) {
  7. sleep(5000);
  8. var orderId = Math.floor(Math.random() * (1000 - 1) + 1);
  9. start(orderId).catch((e) => {
  10. console.error(e);
  11. process.exit(1);
  12. });
  13. }
  14. }
  15. //Invoke a service
  16. const result = await axios.post('order-processor' , "orders/" + orderId , axiosConfig);
  17. console.log("Order requested: " + orderId);
  18. console.log("Result: " + result.config.data);
  19. function sleep(ms) {
  20. return new Promise(resolve => setTimeout(resolve, ms));
  21. }
  22. main();
  1. //dependencies
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Net.Http;
  5. using System.Net.Http.Headers;
  6. using System.Threading.Tasks;
  7. using Microsoft.AspNetCore.Mvc;
  8. using System.Threading;
  9. //code
  10. namespace EventService
  11. {
  12. class Program
  13. {
  14. static async Task Main(string[] args)
  15. {
  16. while(true) {
  17. await Task.Delay(5000)
  18. var random = new Random();
  19. var orderId = random.Next(1,1000);
  20. //Using Dapr SDK to invoke a method
  21. var order = new Order("1");
  22. var orderJson = JsonSerializer.Serialize<Order>(order);
  23. var content = new StringContent(orderJson, Encoding.UTF8, "application/json");
  24. var httpClient = DaprClient.CreateInvokeHttpClient();
  25. await httpClient.PostAsJsonAsync($"http://order-processor/orders", content);
  26. Console.WriteLine("Order requested: " + orderId);
  27. Console.WriteLine("Result: " + result);
  28. }
  29. }
  30. }
  31. }
  1. //dependencies
  2. import java.io.IOException;
  3. import java.net.URI;
  4. import java.net.http.HttpClient;
  5. import java.net.http.HttpRequest;
  6. import java.net.http.HttpResponse;
  7. import java.time.Duration;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. import java.util.Random;
  11. import java.util.concurrent.TimeUnit;
  12. //code
  13. @SpringBootApplication
  14. public class CheckoutServiceApplication {
  15. private static final HttpClient httpClient = HttpClient.newBuilder()
  16. .version(HttpClient.Version.HTTP_2)
  17. .connectTimeout(Duration.ofSeconds(10))
  18. .build();
  19. public static void main(String[] args) throws InterruptedException, IOException {
  20. while (true) {
  21. TimeUnit.MILLISECONDS.sleep(5000);
  22. Random random = new Random();
  23. int orderId = random.nextInt(1000 - 1) + 1;
  24. // Create a Map to represent the request body
  25. Map<String, Object> requestBody = new HashMap<>();
  26. requestBody.put("orderId", orderId);
  27. // Add other fields to the requestBody Map as needed
  28. HttpRequest request = HttpRequest.newBuilder()
  29. .POST(HttpRequest.BodyPublishers.ofString(new JSONObject(requestBody).toString()))
  30. .uri(URI.create(dapr_url))
  31. .header("Content-Type", "application/json")
  32. .header("dapr-app-id", "order-processor")
  33. .build();
  34. HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
  35. System.out.println("Order passed: " + orderId);
  36. TimeUnit.MILLISECONDS.sleep(1000);
  37. log.info("Order requested: " + orderId);
  38. log.info("Result: " + response.body());
  39. }
  40. }
  41. }
  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "log"
  6. "math/rand"
  7. "net/http"
  8. "os"
  9. "time"
  10. )
  11. func main() {
  12. daprHttpPort := os.Getenv("DAPR_HTTP_PORT")
  13. if daprHttpPort == "" {
  14. daprHttpPort = "3500"
  15. }
  16. client := &http.Client{
  17. Timeout: 15 * time.Second,
  18. }
  19. for i := 0; i < 10; i++ {
  20. time.Sleep(5000)
  21. orderId := rand.Intn(1000-1) + 1
  22. url := fmt.Sprintf("http://localhost:%s/checkout/%v", daprHttpPort, orderId)
  23. req, err := http.NewRequest(http.MethodGet, url, nil)
  24. if err != nil {
  25. panic(err)
  26. }
  27. // Adding target app id as part of the header
  28. req.Header.Add("dapr-app-id", "order-processor")
  29. // Invoking a service
  30. resp, err := client.Do(req)
  31. if err != nil {
  32. log.Fatal(err.Error())
  33. }
  34. b, err := io.ReadAll(resp.Body)
  35. if err != nil {
  36. panic(err)
  37. }
  38. fmt.Println(string(b))
  39. }
  40. }

其他 URL 格式

要调用 ‘GET’ 端点:

  1. curl http://localhost:3602/v1.0/invoke/checkout/method/checkout/100

为了尽可能避免改变 URL 路径,Dapr 提供了以下方式来调用服务调用API:

  1. 将 URL 中的地址改为 localhost:<dapr-http-port>
  2. 添加一个 dapr-app-id header 来指定目标服务的ID,或者通过 HTTP Basic Auth 传递 ID:http://dapr-app-id:<service-id>@localhost:3602/path

例如,以下命令:

  1. curl http://localhost:3602/v1.0/invoke/checkout/method/checkout/100

等同于:

  1. curl -H 'dapr-app-id: checkout' 'http://localhost:3602/checkout/100' -X POST

或者:

  1. curl 'http://dapr-app-id:checkout@localhost:3602/checkout/100' -X POST

使用 CLI:

  1. dapr invoke --app-id checkout --method checkout/100

命名空间

当在支持命名空间的平台上运行时,您需要在应用ID中包含目标应用的命名空间。 例如,按照 <app>.<namespace> 格式,使用 checkout.production

使用此示例,调用带有命名空间的服务将如下所示:

  1. curl http://localhost:3602/v1.0/invoke/checkout.production/method/checkout/100 -X POST

查看有关命名空间的更多信息,请参阅跨命名空间API规范

查看跟踪和日志

上面的示例显示了如何直接调用本地或 Kubernetes 中运行的其他服务。 Dapr:

  • 输出指标、追踪和日志信息,
  • 允许您可视化服务之间的调用图并记录错误日志,以及
  • (可选)记录有效负载正文。

了解有关跟踪和日志的更多信息,请参阅可观测性文章。

相关链接