为本站开发抖音小程序,到支付时,看了抖音官方文档,没有C#版本的,百度了几下,也是没有找到,本人是小白,就自己摸索了一下,总结如下,支付模式与微信小程序不一样。微信小程序下单流程是通过自已服务器下单,而抖音是通过自己服务器生成data和byteAuthorization,反回给前端,前端使用tt.requestOrder下单,获取订单号后调用tt.getOrderPayment发起支付,总体来说,还是比较复杂的,所以把开发过程记录下来,希望能够帮助有需要的。
一、开通通用交易系统OpenApi接口能力以及开通支付能力
(一)开通通用交易系统OpenApi接口能力。进入小程序控制台->能力->解决方案->交易类小程序通用,开通过过程需要填写预期使用场景和场景示意图。
预期使用场景:(如)在客户置顶信息是需要付费用。
场景示意图:就截图你已开发小程序需要支付的界面即可。
但我猜审核是系统审核,一般5分钟就开通了。
(二)开通支付能力。
进入小程序控制台->支付-支付能力,企业申请开通企事担保交易,个人的话也申请开通个人担保,开通后,可支持支付宝、微信支付。这一步需要准备法人证件,营业执照等。
二、类目配置
进入小程序控制台->设置->基础设置->类目与配置(点击去管理)-添加类目。这里的类目需要根据自己的实际需求进行填写。部分类目需要上传佐证资料。如果信息类的,建议选择工具-信息查询等,不需要上传其它辅助资料。
三、生成私钥与公钥
官方生成地址: https://developer.open-douyin.com/docs/openapi-explorer/sign ,选择PKCS8(JAVA适用),如下图

把生成的好的私钥和公钥复制,保存好,我使用的是privatekey.txt和publickey.txt保存在api目录下。以便调用,保存好之后,还需要把公钥上传到服务器:进入小程序控制台->开发->开发配置->密钥设置 把公钥粘贴进去->保存。
四、查询标签组信息
这一步,我直接填写官方文档上的goods_type和tag_group_id是不行的,还是需要写用httpclient发送post。方法如下:
(一)获取access_token
获取AppID和AppSecret,进入小程序控制台->开发->开发配置,复制AppID,生成AppSecret不直接显示,生成一次记得复制保存。

public static async Task<string> GetClientTokenAsync(string appId, string appSecret)
{
try
{
// 1. 构建请求参数 (application/x-www-form-urlencoded)
var parameters = new Dictionary<string, string>
{
{ "client_key", appId },
{ "client_secret", appSecret },
{ "grant_type", "client_credential" }
};
using var content = new FormUrlEncodedContent(parameters);
// 2. 发送 POST 请求
var response = await _httpClient.PostAsync("https://open.douyin.com/oauth/client_token/", content);
var responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
catch (Exception ex)
{
Console.WriteLine($"请求异常: {ex.Message}");
return null;
}
}
(二)获取goods_type和tag_group_id,GoodsType = 302这里需要根据你的类目来找,可以官方网站上获取。
public async Task<string> GetTypeAndTagid(string appId, string appSecret)
{
string tagGroupId = null;
string token = await requestOrder.GetClientTokenAsync(appId,, appSecret);
var token1= JObject.Parse(token);
string accessToken=token1["data"]["access_token"].ToString();
string url = "https://open.douyin.com/api/trade_basic/v1/developer/tag_query/";
HttpClient _httpClient= new HttpClient();
// 2. 构建请求头
_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Add("access-token", accessToken);
// 3. 构建请求体
var request = new TagQueryRequest
{
GoodsType = 302
};
string json = JsonConvert.SerializeObject(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// 4. 发送请求
using var response = await _httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
string responseJson = await response.Content.ReadAsStringAsync();
return responseJson;
}
public class TagQueryRequest
{
[JsonProperty("goods_type")]
public int GoodsType { get; set; }
}
这一步下面,就能获取goods_type和tag_group_id,因为可能官网变化后,tag_group_id不一样,导致支付不了。
五、生成生成下单参数与签名
这一步非常关键,把这一步做好,后面基本就不成问题了。
(一)生成data,直接上方法
public static string BuildDouyinPayData(string outOrderNo, int totalAmount, string skuId, string title, string payNotifyUrl, string tagGroupId,string url,string myparams)
{
// 构造官方格式对象
var payData = new
{
skuList = new[]
{
new
{
skuId = skuId,
price = totalAmount*100, // 单商品,价格=总金额
quantity = 1,//数量
title = title,//商品标题
imageList = new[] { "https://www.xxxxxx.com/xxxx.png" }, // 可替换,商品图片
type = 301, // 固定值 就就是第四步获取的goods_type
tagGroupId = tagGroupId //第四步获取的tag_group_id
}
},
outOrderNo = outOrderNo, //你自己的订单号
totalAmount = totalAmount*100,//这里如果是多个商品,还需要*quantity
payExpireSeconds = 300, // 5分钟
orderEntrySchema = new { path =url, @params=myparams },//path为小程序业务路径,params为参数:“
{\"orderId\":\"123456\",\"userId\":\"12345678\"}"这种格式,特别重要,不要写错了
payNotifyUrl = payNotifyUrl;//回调的url,就是支付成功后,返回给你api地址
};
// 序列化为 JSON(无格式化,符合抖音要求)
return JsonConvert.SerializeObject(payData, Formatting.None);
}
(二)生成byteAuthorization
string data = BuildDouyinPayData(参数...)
string urlPath = "/requestOrder"; //这里一定是这个,不要更改
var auth = CreateByteAuthorization("POST", urlPath, data);//这条就是签名。
1. CreateByteAuthorization方法
public static string CreateByteAuthorization(string httpMethod, string urlPath, string requestBodyJson)
{
// 1. 生成时间戳和随机串
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
var nonceStr = Guid.NewGuid().ToString("N"); // 官方示例使用 UUID 去掉横线
// 2. 构造待签名字符串(5行,每行以 \n 结尾)
var signContent = $"{httpMethod}\n{urlPath}\n{timestamp}\n{nonceStr}\n{requestBodyJson}\n";
// 3. 使用私钥签名
var signature = Sign(signContent);
// 4. 构造 Byte-Authorization Header(注意参数名是 appid)
return $"SHA256-RSA2048 appid={AppId},nonce_str={nonceStr},timestamp={timestamp},key_version=
{KeyVersion},signature={signature}";
}
2. Sign方法
public static string Sign(string content)
{
using var rsa = LoadPrivateKey();
var dataBytes = Encoding.UTF8.GetBytes(content);
var signBytes = rsa.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signBytes);
}
3.LoadPrivateKey()方法
public static RSA LoadPrivateKey()
{
var privateKeyPem = File.ReadAllText(Directory.GetCurrentDirectory()+ "/xxx/privatekey.txt");//放置privatekey.txt的位置
var pem = privateKeyPem
.Replace("-----BEGIN PRIVATE KEY-----", "")
.Replace("-----END PRIVATE KEY-----", "")
.Replace("\r", "")
.Replace("\n", "")
.Trim();
var privateKeyBytes = Convert.FromBase64String(pem);
var rsa = RSA.Create();
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
return rsa;
}
好,生成data和byteAuthorization(上面的auth)返回给前端。
六、发起支付
tt.requestOrder({
data:data
byteAuthorization: auth, // 开发者服务端返回的byteAuthorization
success: (res) => {
tt.getOrderPayment({
orderId: res.orderId, // 替换为抖音开放平台内部的交易订单号
success: (ress) => {
console.log("支付成功", ress);
//把相关支付结果回传api
tt.showToast({
icon: "success",
title: "支付成功",
});
},
fail: (ress) => {
console.error("支付失败", ress);
const { errNo, errMsg } = ress;
tt.showToast({
icon: "fail",
title: "支付失败",
});
},
});
},
fail: (res) => {
const { errLogId, errMsg, errNo } = res;
console.log("errNo:", errNo);
console.log("errMsg:", errMsg);
},
});。
按照本文思路,能够实现支付,建议开发过程中,一定要注意安全问题,上述代码只是实现部分核心关键。本文为
原创,转载请标明来自己无忧酒店交易网。