1. 接口规则
为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考APIv3接口规则。
2. 开发准备
2.1. 搭建和配置开发环境
开发者应当依据自身的编程语言来构建并配置相应的开发环境。
2.2. 业务开发配置
合单支付目前支持在微信外H5、App、JSAPI、小程序、Native扫码5个场景使用,下面为你介绍App场景业务开发配置。
2.2.1. 注册App
App接入微信支付,需要先将商户App在微信开放平台进行注册,登记App开发参数以生成AppID。具体操作步骤如下:
1.登录微信开放平台,进入【管理中心 → 移动应用 → 创建移动应用】;
2.完成基本信息的录入,商户需要在本步骤提交App对应的下载地址,应用官网,应用水印,icon等业务信息;
3.完成平台信息的录入,商户需要在本步骤提交App在Android及iOS端对应的开发参数,包括Android端应用的包名,应用签名,iOS端应用的bundle ID, universal link等;
4.以上信息全部提交完成后,即完成App的注册,商户可在【管理中心 → 移动应用】中,选择具体的应用查看其AppID及已获得的接口能力;
5.获取到App的AppID后,需要将该AppID与商户的收款mchid进行绑定,商户可登录商户平台后前往【产品中心 > AppID账号管理】界面中进行AppID的绑定及管理,界面如图所示:
2.2.2. iOS开发要点说明
1、iOS系统OpenSDK升级指引
由于苹果公司在iOS13系统回收了查询 App bundleID 的能力,导致微信无法保证授权凭证能正确返回给AppID对应的应用。为此,微信支付强烈要求所有商户尽快升级到OpenSDK1.8.6,并让用户及时更新App,否则安全风险将一直存在。谢谢配合!
详细OpenSDK升级指引请参见:OpenSDK升级指引
| 注意 OpenSDK升级后请一定按照文档要求完成验证工作,确保OpenSDK升级成功。 |
|
2、开发配置:
以下项目开发环境以Xcode6.0,运行环境为IOS7.0为例,说明其开发中需要的操作
a.项目设置AppID
商户在微信开放平台申请开发App应用后,微信开放平台会生成App的唯一标识AppID。在Xcode中打开项目,设置项目属性中的URL Schemes为您的AppID。如图标红位置所示
b. 注册AppID
商户App工程中引入微信lib库和头文件,调用API前,需要先向微信注册您的AppID,代码如下:
1[WXApi registerApp:@"wxd930ea5d5a258f4f" withDescription:@"demo 2.0"];
| 注意 OpenSDK前端拉起支付及SDK回调的相关说明,请参考App调起支付 |
|
2.2.3. Android开发要点说明
1、后台设置
商户在微信开放平台申请开发应用后,微信开放平台会生成App的唯一标识AppID。由于需要保证支付安全,需要在开放平台绑定商户应用包名和应用签名,设置好后才能正常发起支付。设置界面在【开放平台】中的栏目【管理中心 / 修改应用 / 修改开发信息】里面,如图红框内所示。
应用包名:是在App项目配置文件AndroidManifest.xml中声明的package
值,例如上图中的package="demo.wxpay.tenpay.com"
。
应用签名:根据项目的应用包名和编译使用的keystore,可由签名工具生成一个32位的md5串,在调试的手机上安装签名工具后,运行可生成应用签名串,如图8.9所示,绿色串即应用签名。点击下载签名生成工具
2、注册AppID
商户App工程中引入微信JAR包,调用API前,需要先向微信注册您的AppID,代码如下:
final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);
// 将该app注册到微信
msgApi.registerApp("wxd930ea5d5a258f4f");
3. 快速接入
3.1. 业务流程图
业务流程时序图如下。
重点步骤说明:
步骤1:用户在商户侧发起支付请求,商户先通过后台接口合单下单-App接口创建合单支付订单。
步骤2:商户再根据用户发起支付请求的具体场景通过App页面调起微信支付收银台,完成支付请求。
步骤4:如果商户长时间未收到回调通知,可通过合单查询订单接口主动查询订单支付状态。
3.2. API接入(含示例代码)
文档展示了如何使用微信支付服务端 SDK 快速接入支付有礼,完成与微信支付对接的部分。
3.2.1. 【服务端】App下单
步骤说明:用户在商户App内完成商户选择后进入支付页面,商户需要通过后端请求该App下单API来获取预支付ID。
JAVA代码示例:
1public void CombineJsapiPrepay() throws Exception{
2
3 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/combine-transactions/app");
4
5
6 String reqdata = "{"
7 + "\"combine_out_trade_no\":\"1217752501201407033233368018\","
8 + "\"combine_mchid\":\"1230000109\","
9 + "\"combine_appid\":\"wxd678efh567hg6787\","
10 + "\"scene_info\": {"
11 + "\"device_id\":\"POS1:1\","
12 + "\"payer_client_ip\":\"14.17.22.32\""
13 + "},"
14 + "\"sub_orders\": ["
15 + "{"
16 + "\"mchid\":\"1230000109\","
17 + "\"attach\":\"深圳分店\","
18 + "\"amount\": {"
19 + "\"total_amount\":10,"
20 + "\"currency\":\"CNY\""
21 + "},"
22 + "\"out_trade_no\":\"20150806125346\","
23 + "\"sub_mchid\":\"1900000109\","
24 + "\"description\":\"腾讯充值中心-QQ会员充值\""
25 + "}"
26 + "],"
27 + "\"combine_payer_info\": {"
28 + "\"openid\":\"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o\""
29 + "},"
30 + "\"time_start\":\"2018-06-08T10:34:56+08:00\","
31 + "\"time_expire\":\"2018-06-08T10:34:56+08:00\","
32 + "\"notify_url\":\"https://yourapp.com/notify\""
33 + "}";
34 StringEntity entity = new StringEntity(reqdata,"utf-8");
35 entity.setContentType("application/json");
36 httpPost.setEntity(entity);
37 httpPost.setHeader("Accept", "application/json");
38
39
40 CloseableHttpResponse response = httpClient.execute(httpPost);
41
42 try {
43 int statusCode = response.getStatusLine().getStatusCode();
44 if (statusCode == 200) {
45 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
46 } else if (statusCode == 204) {
47 System.out.println("success");
48 } else {
49 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
50 throw new IOException("request failed");
51 }
52 } finally {
53 response.close();
54 }
55}
PHP代码示例:
1try {
2 $resp = $client->request(
3 'POST',
4 'https://api.mch.weixin.qq.com/v3/combine-transactions/app',
5 [
6
7 'json' => [
8 "combine_out_trade_no" => "1217752501201407033233368018",
9 "combine_mchid" => "1230000109",
10 "combine_appid" => "wxd678efh567hg6787",
11 "scene_info" => [
12 "device_id" => "POS1:1",
13 "payer_client_ip" => "14.17.22.32",
14 ],
15 "sub_orders" => [
16 [
17 "mchid" => "1230000109",
18 "attach" => "深圳分店",
19 "amount" => [
20 "total_amount" => 10,
21 "currency" => "CNY",
22 ],
23 "out_trade_no" => "20150806125346",
24 "sub_mchid" => "1900000109",
25 "description" => "腾讯充值中心-QQ会员充值",
26 ],
27 ],
28 "combine_payer_info" => [
29 "openid" => "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o",
30 ],
31 "time_start" => "2018-06-08T10:34:56+08:00",
32 "time_expire" => "2018-06-08T10:34:56+08:00",
33 "notify_url" => "https://yourapp.com/notify",
34 ],
35 'headers' => [ 'Accept' => 'application/json' ]
36 ]
37 );
38 $statusCode = $resp->getStatusCode();
39 if ($statusCode == 200) {
40 echo "success,return body = " . $resp->getBody()->getContents()."\n";
41 } else if ($statusCode == 204) {
42 echo "success";
43 }
44} catch (RequestException $e) {
45
46 echo $e->getMessage()."\n";
47 if ($e->hasResponse()) {
48 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
49 }
50 return;
51}
重要入参说明:
out_trade_no:商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一
description:商品描述
notify_url:支付回调通知URL,该地址必须为直接可访问的URL,不允许携带查询串
total:订单总金额,单位为分
OpenID:OpenID是微信用户在AppID下的唯一用户标识(AppID不同,则获取到的OpenID就不同),可用于永久标记一个用户。OpenID获取方式请参考以下文档小程序获取OpenID、公众号获取OpenID、App获取OpenID。
更多参数、响应详情及错误码请参见合单下单-App。
3.2.2. 【客户端】App调起支付
步骤说明:通过App下单API成功获取预支付交易会话标识(prepay_id
) 后,需要通过OpenSDK来调起微信支付收银台。
iOS SDK调用说明
1、拉起支付
商户服务器生成支付订单,先调用合单App下单API生成预付单,获取到prepay_id后将参数再次签名传输给App发起支付。以下是调起微信支付的关键代码:
1PayReq *request = [[[PayReq alloc] init] autorelease];
2request.partnerId = @"10000100";
3request.prepayId= @"1101000000140415649af9fc314aa427";
4request.package = @"Sign=WXPay";
5request.nonceStr= @"a462b76e7436e98e0ed6e13c64b4fd1c";
6request.timeStamp= @"1397527777";
7request.sign= @"582282D72DD2B03AD892830965F428CB16E7A256";
8[WXApi sendReq:request]
2、SDK结果回调
按照微信SDK Sample,在类实现onResp函数,支付完成后,微信App会返回到商户App并回调onResp函数,开发者需要在该函数中接收通知,判断返回错误码。如果支付成功则去后台查询支付结果再展示用户实际支付结果。注意一定不能以客户端返回作为用户支付的结果,应以服务器端接收的支付通知或查询API返回的结果为准。
代码示例如下:
1-(void)onResp:(BaseResp*)resp{
2 if ([respisKindOfClass:[PayRespclass]]){
3 PayResp*response=(PayResp*)resp;
4 switch(response.errCode){
5 caseWXSuccess:
6 NSlog(@"支付成功");
7 break;
8 default:
9 NSlog(@"支付失败,retcode=%d",resp.errCode);
10 break;
11 }
12 }
13}
回调中errCode值列表:
|
0 | 成功 | 展示成功页面 |
-1 | 错误 | 可能的原因:签名错误、未注册AppID、项目设置AppID不正确、注册的AppID与设置的不匹配、其他异常等。 |
-2 | 用户取消 | 无需处理。发生场景:用户不支付了,点击取消,返回App。 |
Android SDK调用说明
1、SDK拉起支付
商户服务器生成支付订单,先调用App下单API生成预付单,获取到prepay_id后将参数再次签名传输给App发起支付。以下是调起微信支付的关键代码:
1IWXAPI api;
2PayReq request = new PayReq();
3request.appId = "wxd930ea5d5a258f4f";
4request.partnerId = "1900000109";
5request.prepayId= "1101000000140415649af9fc314aa427",;
6request.packageValue = "Sign=WXPay";
7request.nonceStr= "1101000000140429eb40476f8896f4c9";
8request.timeStamp= "1398746574";
9request.sign= "7FFECB600D7157C5AA49810D2D8F28BC2811827B";
10api.sendReq(request);
2、支付结果回调
参照微信SDK Sample,在商户包名.wxapi包路径中实现WXPayEntryActivity类(包名或类名不一致会造成无法回调),在WXPayEntryActivity类中实现onResp函数,支付完成后,微信App会返回到商户App并回调onResp函数,开发者需要在该函数中接收通知,判断返回错误码。 如果支付成功则去后台查询支付结果再展示用户实际支付结果。注意一定不能以客户端返回作为用户支付的结果,应以服务器端的接收的支付通知或查询API返回的结果为准。代码示例如下:
1public void onResp(BaseRespresp){
2 if(resp.getType()==ConstantsAPI.COMMAND_PAY_BY_WX){
3 Log.d(TAG,"onPayFinish,errCode="+resp.errCode);
4 AlertDialog.Builderbuilder=newAlertDialog.Builder(this);
5 builder.setTitle(R.string.app_tip);
6 }
7}
回调中errCode值列表:
|
0 | 成功 | 展示成功页面 |
-1 | 错误 | 可能的原因:签名错误、未注册AppID、项目设置AppID不正确、注册的AppID与设置的不匹配、其他异常等。 |
-2 | 用户取消 | 无需处理。发生场景:用户不支付了,点击取消,返回App。 |
3.2.3.【服务端】接收支付结果通知
步骤说明: 当用户完成支付,微信会把相关支付结果将通过异步回调的方式通知商户,商户需要接收处理,并按文档规范返回应答。
| 注意 支付结果通知的地址需要在请求合单App下单API时传入notify_url 参数中。 支付结果通知是以POST 方法访问商户设置的通知URL,通知的数据以JSON 格式通过请求主体(BODY)传输。通知的数据包括了加密的支付结果详情。 加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头Wechatpay-Signature 。商户应当验证签名,以确认请求来自微信,而不是其他的第三方。签名验证的算法请参考 《微信支付API v3签名验证》。 支付结果通知HTTP应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。 商户成功接收到回调通知后应返回成功的HTTP应答码为200或204 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信会判定本次通知失败,重新发送通知,直到成功为止,但微信不保证通知最终一定能成功。
商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄露导致出现“假通知”,造成资金损失。 当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。 技术人员可登进微信商户后台扫描加入接口报警群,获取接口告警信息。
|
|
更多参数、响应详情及错误码请参见支付结果通知API接口文档。
3.2.4. 【服务端】合单查询订单
步骤说明: 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知时,商户可通过查询订单接口核实订单支付状态。
示例代码:
JAVA示例代码:
1public void QueryOrder() throws Exception {
2
3
4 URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/combine-transactions/out-trade-no/P11093730578574");
5 uriBuilder.setParameter("mchid", mchId);
6
7
8 HttpGet httpGet = new HttpGet(uriBuilder.build());
9 httpGet.addHeader("Accept", "application/json");
10 CloseableHttpResponse response = httpClient.execute(httpGet);
11
12 try {
13 int statusCode = response.getStatusLine().getStatusCode();
14 if (statusCode == 200) {
15 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
16 } else if (statusCode == 204) {
17 System.out.println("success");
18 } else {
19 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
20 throw new IOException("request failed");
21 }
22 } finally {
23 response.close();
24 }
25}
PHP代码示例:
1try {
2 $resp = $client->request(
3 'GET',
4 'https://api.mch.weixin.qq.com/v3/combine-transactions/out-trade-no/P11093730578574',
5 [
6 'headers' => [ 'Accept' => 'application/json']
7 ]
8 );
9 $statusCode = $resp->getStatusCode();
10 if ($statusCode == 200) {
11 echo "success,return body = " . $resp->getBody()->getContents()."\n";
12 } else if ($statusCode == 204) {
13 echo "success";
14 }
15} catch (RequestException $e) {
16
17 echo $e->getMessage()."\n";
18 if ($e->hasResponse()) {
19 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
20 }
21 return;
22}
更多参数、响应详情及错误码请参见查询订单API接口文档。
3.2.5. 【服务端】合单关闭订单
步骤说明: 当商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口
示例代码:
JAVA代码示例:
1public void CombineCloseOrder() throws Exception{
2
3
4 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/combine-transactions/out-trade-no/{combine_out_trade_no}/close");
5
6 String reqdata = "{"
7 + "\"combine_appid \":\"wxd678efh567hg6787\","
8 + "\"combine_out_trade_no\":\"P20150806125346\","
9 + "\"sub_orders\": ["
10 + "{"
11 + "\"mchid\":\"1900000109\","
12 + "\"out_trade_no\":\"20150806125346\","
13 + "\"sub_mchid\":\"1230000109\","
14 + "\"description\":\"腾讯充值中心-QQ会员充值\""
15 + "}"
16 + "]"
17 + "}";
18 StringEntity entity = new StringEntity(reqdata,"utf-8");
19 entity.setContentType("application/json");
20 httpPost.setEntity(entity);
21 httpPost.setHeader("Accept", "application/json");
22
23
24 CloseableHttpResponse response = httpClient.execute(httpPost);
25
26 try {
27 int statusCode = response.getStatusLine().getStatusCode();
28 if (statusCode == 200) {
29 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
30 } else if (statusCode == 204) {
31 System.out.println("success");
32 } else {
33 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
34 throw new IOException("request failed");
35 }
36 } finally {
37 response.close();
38 }
39}
PHP代码示例:
1try {
2 $resp = $client->request(
3 'POST',
4 'https://api.mch.weixin.qq.com/v3/combine-transactions/out-trade-no/{combine_out_trade_no}/close',
5 [
6
7 'json' => [
8 "combine_appid " => "wxd678efh567hg6787",
9 "combine_out_trade_no" => "P20150806125346",
10 "sub_orders" => [
11 [
12 "mchid" => "1900000109",
13 "out_trade_no" => "20150806125346",
14 "sub_mchid" => "1230000109",
15 "description" => "腾讯充值中心-QQ会员充值",
16 ],
17 ]
18 ],
19 'headers' => [ 'Accept' => 'application/json' ]
20 ]
21 );
22 $statusCode = $resp->getStatusCode();
23 if ($statusCode == 200) {
24 echo "success,return body = " . $resp->getBody()->getContents()."\n";
25 } else if ($statusCode == 204) {
26 echo "success";
27 }
28} catch (RequestException $e) {
29
30 echo $e->getMessage()."\n";
31 if ($e->hasResponse()) {
32 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
33 }
34 return;
35}
更多参数、响应详情及错误码请参见合单关单API接口文档。
3.2.6. 【服务端】申请交易账单
步骤说明: 微信支付按天提供交易账单文件,商户可以通过该接口获取账单文件的下载地址。
示例代码:
JAVA代码示例:
1public void TradeBill() throws Exception {
2
3
4 URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/bill/tradebill");
5 uriBuilder.setParameter("bill_date", "2020-11-09");
6 uriBuilder.setParameter("bill_type", "ALL");
7
8
9 HttpGet httpGet = new HttpGet(uriBuilder.build());
10 httpGet.addHeader("Accept", "application/json");
11 CloseableHttpResponse response = httpClient.execute(httpGet);
12
13 try {
14 int statusCode = response.getStatusLine().getStatusCode();
15 if (statusCode == 200) {
16 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
17 } else if (statusCode == 204) {
18 System.out.println("success");
19 } else {
20 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
21 throw new IOException("request failed");
22 }
23 } finally {
24 response.close();
25 }
26}
PHP代码示例:
1try {
2 $resp = $client->request(
3 'GET',
4 'https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2019-06-11&sub_mchid=1900000001&bill_type=ALL',
5 [
6 'headers' => [ 'Accept' => 'application/json']
7 ]
8 );
9 $statusCode = $resp->getStatusCode();
10 if ($statusCode == 200) {
11 echo "success,return body = " . $resp->getBody()->getContents()."\n";
12 } else if ($statusCode == 204) {
13 echo "success";
14 }
15} catch (RequestException $e) {
16
17 echo $e->getMessage()."\n";
18 if ($e->hasResponse()) {
19 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
20 }
21 return;
22}
更多参数、响应详情及错误码请参见申请交易账单API接口文档。
3.2.7. 【服务端】下载账单
步骤说明: 通过申请交易账单接口获取到账单下载地址(download_url)后,再通过该接口获取到对应的账单文件,文件内包含交易相关的金额、时间、营销等信息,供商户核对订单、退款、银行到账等情况。
示例代码:
JAVA代码示例:
1public void TradeBill() throws Exception {
2
3
4 URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/bill/tradebill");
5 uriBuilder.setParameter("bill_date", "2020-11-09");
6 uriBuilder.setParameter("bill_type", "ALL");
7
8
9 HttpGet httpGet = new HttpGet(uriBuilder.build());
10 httpGet.addHeader("Accept", "application/json");
11 CloseableHttpResponse response = httpClient.execute(httpGet);
12
13 try {
14 int statusCode = response.getStatusLine().getStatusCode();
15 if (statusCode == 200) {
16 System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
17 } else if (statusCode == 204) {
18 System.out.println("success");
19 } else {
20 System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
21 throw new IOException("request failed");
22 }
23 } finally {
24 response.close();
25 }
26}
PHP代码示例:
1try {
2 $resp = $client->request(
3 'GET',
4 'https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2019-06-11&sub_mchid=1900000001&bill_type=ALL',
5 [
6 'headers' => [ 'Accept' => 'application/json']
7 ]
8 );
9 $statusCode = $resp->getStatusCode();
10 if ($statusCode == 200) {
11 echo "success,return body = " . $resp->getBody()->getContents()."\n";
12 } else if ($statusCode == 204) {
13 echo "success";
14 }
15} catch (RequestException $e) {
16
17 echo $e->getMessage()."\n";
18 if ($e->hasResponse()) {
19 echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
20 }
21 return;
22}
4. 常见问题
问: 获取OpenID接口报“此公众号并没有这些scope的权限,错误码10005”,如下图所示。
建议检查一下公众号的功能。比如是不是在订阅号/未认证的公众号里面尝试调用认证服务号的功能。
确认AppID是否认证过期或者AppID填写错误。
请尝试使用snsapi_userinfo的授权登录方式。
问:获取OpenID接口报“redirect_url域名与后台配置不一致,错误码:10003”。
本错误是公众号获取OpenID接口报的错误,可参考文档检查是否符合开发规范:网页授权
检查下单接口传的AppID与获取OpenID接口的AppID是否同一个(需一致)。
检查AppID对应的公众号后台,是否配置的授权域名和获取OpenID的域名一致。授权域名配置路径:【公众平台-> 设置-> 公众号设置-> 功能设置–> 网页授权域名】。