服务间调用

更新时间 2024-07-24 02:58:49
收藏
我的收藏

介绍 ​

小程序的后台服务有时会拆分成多个服务,抖音云支持同一个小程序下的服务之间通过调用服务对应绑定域名"{{源服务ID-目标服务ID}}.dycloud.service"来进行内网下的服务间调用。 ​

使用限制 ​

服务间调用只支持HTTP协议 ​

操作指引 ​

    1.部署 发起调用的服务 A、被调用的目标服务 B。​
    2.在 来源服务的「访问控制-服务间调用」勾选目标服务,下方会展示对应的调用域名,该域名为内网域名,仅限在服务间调用。​

完整示例 ​

Golang ​

Plain Text
复制
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
)
// GET请求调用
func InternalCallGet(uri, toServiceID string, paramMap map[string]string, headers map[string]string) (string, error) {
// 从环境变量中获取源服务id(即当前服务id)
fromServiceID := os.Getenv("SERVICE_ID")
// 构造url
urlValue := &url.URL{
Scheme: "http",
Host: fmt.Sprintf("%s-%s.dycloud.service", fromServiceID, toServiceID),
Path: uri,
}
params := url.Values{}
for k, v := range paramMap {
params.Set(k, v)
}
urlValue.RawQuery = params.Encode()
urlPath := urlValue.String()
// 构造Get请求体
req, err := http.NewRequest("GET", urlPath, nil)
if err != nil {
return nil, err
}
// 添加headers
for k, v := range headers {
req.Header.Add(k, v)
}
// 执行Get请求
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
// 判断http状态码是否成功
if resp.StatusCode != 200 {
return "", fmt.Errorf("err statuscode: %d", resp.StatusCode)
}
// 读取响应
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(bodyBytes), nil
}
// POST请求调用
func InternalCallPost(uri, toServiceID string, body io.Reader, headers map[string]string) (string, error) {
// 从环境变量中获取源服务id(即当前服务id)
fromServiceID := os.Getenv("SERVICE_ID")
// 构造url
urlPath := fmt.Sprintf("http://%s-%s.dycloud.service%s", fromServiceID, toServiceID, uri)
// 构造POST请求体
req, err := http.NewRequest("POST", urlPath, body)
if err != nil {
return nil, err
}
// 添加headers
for k, v := range headers {
req.Header.Add(k, v)
}
// 执行POST请求
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
// 判断http状态码是否成功
if resp.StatusCode != 200 {
return "", fmt.Errorf("err statuscode: %d", resp.StatusCode)
}
// 读取响应
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(bodyBytes), nil
}

Java ​

Plain Text
复制
package com.demo.dyc.internal_call_java.utils;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InternalCallUtil {
// GET请求调用
public static String InternalCallGet(String uri, String toServiceID, HashMap<String, String> paramMap, HashMap<String, String> headers) throws Exception {
// 从环境变量中获取源服务id(即当前服务id)
String fromServiceID = System.getenv("SERVICE_ID");
// 构造url
String url = String.format("http://%s-%s.dycloud.service%s", fromServiceID, toServiceID, uri);
// 构造POST请求体
HttpGet httpGet = new HttpGet(url);
// 表单参数
List<NameValuePair> nvps = new ArrayList<>();
// GET 请求参数
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
// 将参数增加到请求 URL 中
try {
URI uriVariable = new URIBuilder(new URI(url))
.addParameters(nvps)
.build();
httpGet.setURI(uriVariable);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
// 添加header
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpGet.addHeader(entry.getKey(), entry.getValue());
}
// 执行GET请求并读取响应
try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
try (CloseableHttpResponse response = httpclient.execute(httpGet)) {
int statusCode = response.getStatusLine().getStatusCode();
// 判断http状态码是否成功
if (statusCode != 200) {
response.close();
throw new Exception(String.valueOf(statusCode));
}
String content = EntityUtils.toString(response.getEntity());
response.close();
return content;
}
} catch (IOException | ParseException e) {
e.printStackTrace();
throw e;
}
}
// POST请求调用
public static String InternalCallPost(String uri, String toServiceID, String body, HashMap<String, String> headers) throws Exception {
// 从环境变量中获取源服务id(即当前服务id)
String fromServiceID = System.getenv("SERVICE_ID");
// 构造url
String url = String.format("http://%s-%s.dycloud.service%s", fromServiceID, toServiceID, uri);
// 构造POST请求体
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new StringEntity(body, ContentType.APPLICATION_JSON));
// 添加header
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpPost.addHeader(entry.getKey(), entry.getValue());
}
// 执行POST请求并读取响应
try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
int statusCode = response.getStatusLine().getStatusCode();
// 判断http状态码是否成功
if (statusCode != 200) {
response.close();
throw new Exception(String.valueOf(statusCode));
}
String content = EntityUtils.toString(response.getEntity());
return content;
}
} catch (IOException | ParseException e) {
e.printStackTrace();
throw e;
}
}
}

Python ​

Plain Text
复制
import os
import requests
# GET请求调用
def internal_call_get(to_service_id, uri, param_map, headers):
# 从环境变量中获取源服务id(即当前服务id)
from_service_id = os.getenv('SERVICE_ID')
# 构造url
url = 'http://%s-%s.dycloud.service%s' % (from_service_id, to_service_id, uri)
# 执行GET请求并读取响应
try:
response = requests.get(url, params=param_map, headers=headers)
# 判断http状态码是否成功
is_normal_status = response.status_code == 200
if not is_normal_status:
response.close()
raise Exception("err statuscode: %d" % response.status_code)
res = response.text
response.close()
return res
except:
raise
# POST请求调用
def internal_call_post(to_service_id, uri, body, headers):
# 从环境变量中获取源服务id(即当前服务id)
from_service_id = os.getenv('SERVICE_ID')
# 构造url
url = 'http://%s-%s.dycloud.service%s' % (from_service_id, to_service_id, uri)
# 执行POST请求并读取响应
try:
response = requests.post(url, data=body, headers=headers)
# 判断http状态码是否成功
is_normal_status = response.status_code == 200
if not is_normal_status:
response.close()
raise Exception("err statuscode: %d" % response.status_code)
res = response.text
response.close()
return res
except:
raise

Nodejs ​

Plain Text
复制
const axios = require("axios");
const util = require('util');
// GET请求调用
async function internalCallGet(uri, toServiceID, paramMap, headers) {
// 从环境变量中获取源服务id(即当前服务id)
let fromServiceID = process.env.SERVICE_ID;
// 构造url
let url = util.format("http://%s-%s.dycloud.service%s", fromServiceID, toServiceID, uri)
// 添加headers
let reqInstance = axios.create({
headers: headers
})
// 执行GET请求并读取响应
try {
let res = await reqInstance.get(url, {"params": paramMap});
// 判断http状态码是否成功
if (res.status != 200) {
throw new Error(util.format("err statuscode: %d", res.status));
}
return res.data;
} catch(err) {
throw err;
}
}
// POST请求调用
async function internalCallPost(uri, toServiceID, body, headers) {
// 从环境变量中获取源服务id(即当前服务id)
let fromServiceID = process.env.SERVICE_ID;
// 构造url
let url = util.format("http://%s-%s.dycloud.service%s", fromServiceID, toServiceID, uri)
// 添加headers
let reqInstance = axios.create({
headers: headers
})
// 执行POST请求并读取响应
let res = await reqInstance.post(url, body).catch((err) => {
throw err;
});
// 判断http状态码是否成功
if (res.status != 200) {
throw new Error(util.format("err statuscode: %d", res.status))
}
return res.data;
}

PHP ​

Plain Text
复制
<?php
namespace App\Utils;
use Exception;
class InternalCallUtil {
// GET请求调用
function internal_call_get(string $uri, string $to_service_id, array $param_map, array $headers): string {
// 从环境变量中获取源服务id(即当前服务id)
$from_service_id = getenv("SERVICE_ID");
// 构造url
$url = sprintf("http://%s-%s.dycloud.service%s", $from_service_id, $to_service_id, $uri);
// 启动curl并设置请求参数
$ch = curl_init();
$timeout = 5;
$i = 0;
foreach($param_map as $x=>$x_value) {
if ($i == 0) {
$url .= "?";
}
$url = sprintf("%s%s=%s", $url, $x, $x_value);
if ($i < count($param_map) - 1) {
$url .= "&";
}
$i++;
}
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// 执行GET请求并读取响应
try {
$file_contents = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// 判断http状态码是否成功
if ($http_code != 200) {
curl_close($ch);
throw new Exception(sprintf("err statuscode: %s", $http_code));
}
curl_close($ch);
return $file_contents;
} catch (Exception $e) {
curl_close($ch);
throw $e;
}
}
// POST请求调用
function internal_call_post(string $uri, string $to_service_id, array $body, array $headers): string {
// 从环境变量中获取源服务id(即当前服务id)
$from_service_id = getenv("SERVICE_ID");
// 构造url
$url = sprintf("http://%s-%s.dycloud.service%s", $from_service_id, $to_service_id, $uri);
// 启动curl并设置请求参数
$ch = curl_init();
$timeout = 5;
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
// 执行POST请求并读取响应
try {
$file_contents = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// 判断http状态码是否成功
if ($http_code != 200) {
curl_close($ch);
throw new Exception(sprintf("err statuscode: %s", $http_code));
}
curl_close($ch);
return $file_contents;
} catch (Exception $e) {
curl_close($ch);
throw $e;
}
}
}