服务间调用
收藏
我的收藏介绍
小程序的后台服务有时会拆分成多个服务,抖音云支持同一个小程序下的服务之间通过调用服务对应绑定域名"{{源服务ID-目标服务ID}}.inner-call.dyc.ivolces.com"来进行内网下的服务间调用。
使用限制
服务间调用只支持HTTP协议
操作指引
- 1.部署 发起调用的服务 A、被调用的目标服务 B。
- 2.在 来源服务的「访问控制-服务间调用」勾选目标服务,下方会展示对 应的调用域名,该域名为内网域名,仅限在服务间调用。
完整示例
Golang
package main import ( "fmt" "io" "net/http" "net/url" "os" ) // GET请求调用 path(例):/api/get_result?num=1 func InternalCallGet(path, 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.inner-call.dyc.ivolces.com", fromServiceID, toServiceID), Path: path, } 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请求调用 path(例):/api/post_result func InternalCallPost(path, 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..inner-call.dyc.ivolces.com%s", fromServiceID, toServiceID, path) // 构造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
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请求调用 path(例):/api/get_result?num=1 public static String InternalCallGet(String path, 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.inner-call.dyc.ivolces.com%s", fromServiceID, toServiceID, path); // 构造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请求调用 path(例):/api/post_result public static String InternalCallPost(String path, 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.inner-call.dyc.ivolces.com%s", fromServiceID, toServiceID, path); // 构造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
import os import requests # GET请求调用 path(例):/api/get_result?num=1 def internal_call_get(to_service_id, path, param_map, headers): # 从环境变量中获取源服务id(即当前服务id) from_service_id = os.getenv('SERVICE_ID') # 构造url url = 'http://%s-%s.inner-call.dyc.ivolces.com%s' % (from_service_id, to_service_id, path) # 执行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请求调用 path(例):/api/post_result def internal_call_post(to_service_id, path, body, headers): # 从环境变量中获取源服务id(即当前服务id) from_service_id = os.getenv('SERVICE_ID') # 构造url url = 'http://%s-%s.inner-call.dyc.ivolces.com%s' % (from_service_id, to_service_id, path) # 执行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
const axios = require("axios"); const util = require('util'); // GET请求调用 path(例):/api/get_result?num=1 async function internalCallGet(path, toServiceID, paramMap, headers) { // 从环境变量中获取源服务id(即当前服务id) let fromServiceID = process.env.SERVICE_ID; // 构造url let url = util.format("http://%s-%s.inner-call.dyc.ivolces.com%s", fromServiceID, toServiceID, path) // 添加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请求调用 path(例):/api/post_result async function internalCallPost(path, toServiceID, body, headers) { // 从环境变量中获取源服务id(即当前服务id) let fromServiceID = process.env.SERVICE_ID; // 构造url let url = util.format("http://%s-%s.inner-call.dyc.ivolces.com%s", fromServiceID, toServiceID, path) // 添加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
<?php namespace App\Utils; use Exception; class InternalCallUtil { // GET请求调用 path(例):/api/get_result?num=1 function internal_call_get(string $path, string $to_service_id, array $param_map, array $headers): string { // 从环境变量中获取源服务id(即当前服务id) $from_service_id = getenv("SERVICE_ID"); // 构造url $url = sprintf("http://%s-%s.inner-call.dyc.ivolces.com%s", $from_service_id, $to_service_id, $path); // 启动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请求调用 path(例):/api/post_result function internal_call_post(string $path, string $to_service_id, array $body, array $headers): string { // 从环境变量中获取源服务id(即当前服务id) $from_service_id = getenv("SERVICE_ID"); // 构造url $url = sprintf("http://%s-%s.inner-call.dyc.ivolces.com%s", $from_service_id, $to_service_id, $path); // 启动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; } } }