diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java index 53e5fc69..bd5476d4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java @@ -1,12 +1,13 @@ package me.chanjar.weixin.mp.api; -import java.io.File; -import java.util.concurrent.locks.Lock; - import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.mp.bean.WxMpHostConfig; import me.chanjar.weixin.mp.enums.TicketType; +import java.io.File; +import java.util.concurrent.locks.Lock; + /** * 微信客户端配置存储. * @@ -96,4 +97,8 @@ public interface WxMpConfigStorage { */ boolean autoRefreshToken(); + /** + * 得到微信接口地址域名部分的自定义设置信息. + */ + WxMpHostConfig getHostConfig(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java index 4f24b167..31eca6a4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java @@ -8,6 +8,7 @@ import java.util.concurrent.locks.ReentrantLock; import lombok.Data; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.mp.bean.WxMpHostConfig; import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -179,4 +180,9 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage, Serializabl return true; } + @Override + public WxMpHostConfig getHostConfig() { + return null; + } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index 28b69b98..fc467e99 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -157,13 +157,13 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH @Override public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { - return String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(), + return String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); } @Override public String buildQrConnectUrl(String redirectURI, String scope, String state) { - return String.format(QRCONNECT_URL.getUrl(), this.getWxMpConfigStorage().getAppId(), + return String.format(QRCONNECT_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); } @@ -179,14 +179,14 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH @Override public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { - String url = String.format(OAUTH2_ACCESS_TOKEN_URL.getUrl(), this.getWxMpConfigStorage().getAppId(), + String url = String.format(OAUTH2_ACCESS_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret(), code); return this.getOAuth2AccessToken(url); } @Override public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { - String url = String.format(OAUTH2_REFRESH_TOKEN_URL.getUrl(), this.getWxMpConfigStorage().getAppId(), refreshToken); + String url = String.format(OAUTH2_REFRESH_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), refreshToken); return this.getOAuth2AccessToken(url); } @@ -196,7 +196,7 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH lang = "zh_CN"; } - String url = String.format(OAUTH2_USERINFO_URL.getUrl(), token.getAccessToken(), token.getOpenId(), lang); + String url = String.format(OAUTH2_USERINFO_URL.getUrl(this.getWxMpConfigStorage()), token.getAccessToken(), token.getOpenId(), lang); try { RequestExecutor executor = SimpleGetRequestExecutor.create(this); @@ -209,7 +209,7 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH @Override public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken token) { - String url = String.format(OAUTH2_VALIDATE_TOKEN_URL.getUrl(), token.getAccessToken(), token.getOpenId()); + String url = String.format(OAUTH2_VALIDATE_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), token.getAccessToken(), token.getOpenId()); try { SimpleGetRequestExecutor.create(this).execute(url, null); @@ -252,7 +252,7 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH @Override public String get(WxMpApiUrl url, String queryParam) throws WxErrorException { - return this.get(url.getUrl(), queryParam); + return this.get(url.getUrl(this.getWxMpConfigStorage()), queryParam); } @Override @@ -262,12 +262,12 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH @Override public String post(WxMpApiUrl url, String postData) throws WxErrorException { - return this.post(url.getUrl(), postData); + return this.post(url.getUrl(this.getWxMpConfigStorage()), postData); } @Override public T execute(RequestExecutor executor, WxMpApiUrl url, E data) throws WxErrorException { - return this.execute(executor, url.getUrl(), data); + return this.execute(executor, url.getUrl(this.getWxMpConfigStorage()), data); } /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java index 119376d6..5ac3be31 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java @@ -8,7 +8,6 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpAiOpenService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.enums.AiLangType; -import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.requestexecuter.voice.VoiceUploadRequestExecutor; import java.io.File; @@ -34,7 +33,7 @@ public class WxMpAiOpenServiceImpl implements WxMpAiOpenService { } this.wxMpService.execute(VoiceUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), - String.format(VOICE_UPLOAD_URL.getUrl(), "mp3", voiceId, lang.getCode()), + String.format(VOICE_UPLOAD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), "mp3", voiceId, lang.getCode()), voiceFile); } @@ -46,7 +45,8 @@ public class WxMpAiOpenServiceImpl implements WxMpAiOpenService { @Override public String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException { - String response = this.wxMpService.post(String.format(TRANSLATE_URL.getUrl(), langFrom.getCode(), langTo.getCode()), content); + String response = this.wxMpService.post(String.format(TRANSLATE_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), + langFrom.getCode(), langTo.getCode()), content); WxError error = WxError.fromJson(response, WxType.MP); if (error.getErrorCode() != 0) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java index 4743cc24..a131e3a9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java @@ -13,7 +13,6 @@ import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; import me.chanjar.weixin.mp.bean.kefu.result.*; -import me.chanjar.weixin.mp.enums.WxMpApiUrl; import java.io.File; import java.util.Date; @@ -68,13 +67,14 @@ public class WxMpKefuServiceImpl implements WxMpKefuService { public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException { WxMediaUploadResult responseContent = this.wxMpService .execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), - String.format(KFACCOUNT_UPLOAD_HEAD_IMG.getUrl(), kfAccount), imgFile); + String.format(KFACCOUNT_UPLOAD_HEAD_IMG.getUrl(this.wxMpService.getWxMpConfigStorage()), kfAccount), imgFile); return responseContent != null; } @Override public boolean kfAccountDel(String kfAccount) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL.getUrl(), kfAccount), null); + String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL.getUrl(this.wxMpService.getWxMpConfigStorage()), + kfAccount), null); return responseContent != null; } @@ -94,13 +94,15 @@ public class WxMpKefuServiceImpl implements WxMpKefuService { @Override public WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION.getUrl(), openid), null); + String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION + .getUrl(this.wxMpService.getWxMpConfigStorage()), openid), null); return WxMpKfSessionGetResult.fromJson(responseContent); } @Override public WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST.getUrl(), kfAccount), null); + String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST + .getUrl(this.wxMpService.getWxMpConfigStorage()), kfAccount), null); return WxMpKfSessionList.fromJson(responseContent); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java index 3352b95e..2ceec219 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java @@ -53,7 +53,7 @@ public class WxMpMaterialServiceImpl implements WxMpMaterialService { @Override public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = String.format(MEDIA_UPLOAD_URL.getUrl(), mediaType); + String url = String.format(MEDIA_UPLOAD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), mediaType); return this.wxMpService.execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file); } @@ -72,7 +72,7 @@ public class WxMpMaterialServiceImpl implements WxMpMaterialService { @Override public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { - String url = String.format(MATERIAL_ADD_URL.getUrl(), mediaType); + String url = String.format(MATERIAL_ADD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), mediaType); return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java index da4171fb..a654afb7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java @@ -105,7 +105,8 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService { @Override public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException { try { - String resultUrl = String.format(SHOW_QRCODE_WITH_TICKET.getUrl(), URLEncoder.encode(ticket, StandardCharsets.UTF_8.name())); + String resultUrl = String.format(SHOW_QRCODE_WITH_TICKET.getUrl(this.wxMpService.getWxMpConfigStorage()), + URLEncoder.encode(ticket, StandardCharsets.UTF_8.name())); if (needShortUrl) { return this.wxMpService.shortUrl(resultUrl); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java index 0c00793a..17aec251 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java @@ -8,7 +8,6 @@ import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.mp.api.WxMpConfigStorage; -import me.chanjar.weixin.mp.enums.WxMpApiUrl; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -19,7 +18,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import java.io.IOException; import java.util.concurrent.locks.Lock; -import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL; /** * apache http client方式实现. @@ -67,20 +66,20 @@ public class WxMpServiceHttpClientImpl extends BaseWxMpServiceImplBinary Wang + * @date 2019-06-09 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMpHostConfig { + public static final String API_DEFAULT_HOST_URL = "https://api.weixin.qq.com"; + public static final String MP_DEFAULT_HOST_URL = "https://mp.weixin.qq.com"; + public static final String OPEN_DEFAULT_HOST_URL = "https://open.weixin.qq.com"; + + /** + * 对应于:https://api.weixin.qq.com + */ + private String apiHost; + + /** + * 对应于:https://open.weixin.qq.com + */ + private String openHost; + /** + * 对应于:https://mp.weixin.qq.com + */ + private String mpHost; + + public static String buildUrl(WxMpHostConfig hostConfig, String prefix, String path) { + if (hostConfig == null) { + return prefix + path; + } + + if (hostConfig.getApiHost() != null && prefix.equals(API_DEFAULT_HOST_URL)) { + return hostConfig.getApiHost() + path; + } + + if (hostConfig.getMpHost() != null && prefix.equals(MP_DEFAULT_HOST_URL)) { + return hostConfig.getMpHost() + path; + } + + if (hostConfig.getOpenHost() != null && prefix.equals(OPEN_DEFAULT_HOST_URL)) { + return hostConfig.getOpenHost() + path; + } + + return prefix + path; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java index 2ab5fd70..e25e251e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java @@ -1,6 +1,9 @@ package me.chanjar.weixin.mp.enums; import lombok.AllArgsConstructor; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; + +import static me.chanjar.weixin.mp.bean.WxMpHostConfig.*; /** *
@@ -11,127 +14,125 @@ import lombok.AllArgsConstructor;
  * @author Binary Wang
  */
 public interface WxMpApiUrl {
-  String WX_API_BASE_URL = "https://api.weixin.qq.com";
-  String WX_MP_BASE_URL = "https://mp.weixin.qq.com";
-  String WX_OPEN_BASE_URL = "https://open.weixin.qq.com";
 
   /**
    * 得到api完整地址.
    *
+   * @param config 微信公众号配置
    * @return api地址
    */
-  String getUrl();
+  String getUrl(WxMpConfigStorage config);
 
   @AllArgsConstructor
   enum Device implements WxMpApiUrl {
     /**
      * get_bind_device.
      */
-    DEVICE_GET_BIND_DEVICE(WX_API_BASE_URL, "/device/get_bind_device"),
+    DEVICE_GET_BIND_DEVICE(API_DEFAULT_HOST_URL, "/device/get_bind_device"),
     /**
      * get_openid.
      */
-    DEVICE_GET_OPENID(WX_API_BASE_URL, "/device/get_openid"),
+    DEVICE_GET_OPENID(API_DEFAULT_HOST_URL, "/device/get_openid"),
     /**
      * compel_unbind.
      */
-    DEVICE_COMPEL_UNBIND(WX_API_BASE_URL, "/device/compel_unbind?"),
+    DEVICE_COMPEL_UNBIND(API_DEFAULT_HOST_URL, "/device/compel_unbind?"),
     /**
      * unbind.
      */
-    DEVICE_UNBIND(WX_API_BASE_URL, "/device/unbind?"),
+    DEVICE_UNBIND(API_DEFAULT_HOST_URL, "/device/unbind?"),
     /**
      * compel_bind.
      */
-    DEVICE_COMPEL_BIND(WX_API_BASE_URL, "/device/compel_bind"),
+    DEVICE_COMPEL_BIND(API_DEFAULT_HOST_URL, "/device/compel_bind"),
     /**
      * bind.
      */
-    DEVICE_BIND(WX_API_BASE_URL, "/device/bind"),
+    DEVICE_BIND(API_DEFAULT_HOST_URL, "/device/bind"),
     /**
      * authorize_device.
      */
-    DEVICE_AUTHORIZE_DEVICE(WX_API_BASE_URL, "/device/authorize_device"),
+    DEVICE_AUTHORIZE_DEVICE(API_DEFAULT_HOST_URL, "/device/authorize_device"),
     /**
      * getqrcode.
      */
-    DEVICE_GETQRCODE(WX_API_BASE_URL, "/device/getqrcode"),
+    DEVICE_GETQRCODE(API_DEFAULT_HOST_URL, "/device/getqrcode"),
     /**
      * transmsg.
      */
-    DEVICE_TRANSMSG(WX_API_BASE_URL, "/device/transmsg");
+    DEVICE_TRANSMSG(API_DEFAULT_HOST_URL, "/device/transmsg");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
-  }
 
+  }
 
   @AllArgsConstructor
   enum Other implements WxMpApiUrl {
     /**
      * 获取access_token.
      */
-    GET_ACCESS_TOKEN_URL(WX_API_BASE_URL, "/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"),
+    GET_ACCESS_TOKEN_URL(API_DEFAULT_HOST_URL, "/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"),
     /**
      * 获得各种类型的ticket.
      */
-    GET_TICKET_URL(WX_API_BASE_URL, "/cgi-bin/ticket/getticket?type="),
+    GET_TICKET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/ticket/getticket?type="),
     /**
      * 长链接转短链接接口.
      */
-    SHORTURL_API_URL(WX_API_BASE_URL, "/cgi-bin/shorturl"),
+    SHORTURL_API_URL(API_DEFAULT_HOST_URL, "/cgi-bin/shorturl"),
     /**
      * 语义查询接口.
      */
-    SEMANTIC_SEMPROXY_SEARCH_URL(WX_API_BASE_URL, "/semantic/semproxy/search"),
+    SEMANTIC_SEMPROXY_SEARCH_URL(API_DEFAULT_HOST_URL, "/semantic/semproxy/search"),
     /**
      * 用code换取oauth2的access token.
      */
-    OAUTH2_ACCESS_TOKEN_URL(WX_API_BASE_URL, "/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"),
+    OAUTH2_ACCESS_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"),
     /**
      * 刷新oauth2的access token.
      */
-    OAUTH2_REFRESH_TOKEN_URL(WX_API_BASE_URL, "/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"),
+    OAUTH2_REFRESH_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"),
     /**
      * 用oauth2获取用户信息.
      */
-    OAUTH2_USERINFO_URL(WX_API_BASE_URL, "/sns/userinfo?access_token=%s&openid=%s&lang=%s"),
+    OAUTH2_USERINFO_URL(API_DEFAULT_HOST_URL, "/sns/userinfo?access_token=%s&openid=%s&lang=%s"),
     /**
      * 验证oauth2的access token是否有效.
      */
-    OAUTH2_VALIDATE_TOKEN_URL(WX_API_BASE_URL, "/sns/auth?access_token=%s&openid=%s"),
+    OAUTH2_VALIDATE_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/auth?access_token=%s&openid=%s"),
     /**
      * 获取微信服务器IP地址.
      */
-    GET_CALLBACK_IP_URL(WX_API_BASE_URL, "/cgi-bin/getcallbackip"),
+    GET_CALLBACK_IP_URL(API_DEFAULT_HOST_URL, "/cgi-bin/getcallbackip"),
     /**
      * 第三方使用网站应用授权登录的url.
      */
-    QRCONNECT_URL(WX_OPEN_BASE_URL, "/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"),
+    QRCONNECT_URL(OPEN_DEFAULT_HOST_URL, "/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"),
     /**
      * oauth2授权的url连接.
      */
-    CONNECT_OAUTH2_AUTHORIZE_URL(WX_OPEN_BASE_URL, "/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"),
+    CONNECT_OAUTH2_AUTHORIZE_URL(OPEN_DEFAULT_HOST_URL, "/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"),
     /**
      * 获取公众号的自动回复规则.
      */
-    GET_CURRENT_AUTOREPLY_INFO_URL(WX_API_BASE_URL, "/cgi-bin/get_current_autoreply_info"),
+    GET_CURRENT_AUTOREPLY_INFO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/get_current_autoreply_info"),
     /**
      * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零.
      */
-    CLEAR_QUOTA_URL(WX_API_BASE_URL, "/cgi-bin/clear_quota");
+    CLEAR_QUOTA_URL(API_DEFAULT_HOST_URL, "/cgi-bin/clear_quota");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -140,26 +141,26 @@ public interface WxMpApiUrl {
     /**
      * sets add.
      */
-    USER_ACTION_SETS_ADD(WX_API_BASE_URL, "/marketing/user_action_sets/add?version=v1.0"),
+    USER_ACTION_SETS_ADD(API_DEFAULT_HOST_URL, "/marketing/user_action_sets/add?version=v1.0"),
     /**
      * get.
      */
-    USER_ACTION_SETS_GET(WX_API_BASE_URL, "/marketing/user_action_sets/get"),
+    USER_ACTION_SETS_GET(API_DEFAULT_HOST_URL, "/marketing/user_action_sets/get"),
     /**
      * add.
      */
-    USER_ACTIONS_ADD(WX_API_BASE_URL, "/marketing/user_actions/add?version=v1.0"),
+    USER_ACTIONS_ADD(API_DEFAULT_HOST_URL, "/marketing/user_actions/add?version=v1.0"),
     /**
      * get.
      */
-    WECHAT_AD_LEADS_GET(WX_API_BASE_URL, "/marketing/wechat_ad_leads/get");
+    WECHAT_AD_LEADS_GET(API_DEFAULT_HOST_URL, "/marketing/wechat_ad_leads/get");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -168,38 +169,38 @@ public interface WxMpApiUrl {
     /**
      * get_current_selfmenu_info.
      */
-    GET_CURRENT_SELFMENU_INFO(WX_API_BASE_URL, "/cgi-bin/get_current_selfmenu_info"),
+    GET_CURRENT_SELFMENU_INFO(API_DEFAULT_HOST_URL, "/cgi-bin/get_current_selfmenu_info"),
     /**
      * trymatch.
      */
-    MENU_TRYMATCH(WX_API_BASE_URL, "/cgi-bin/menu/trymatch"),
+    MENU_TRYMATCH(API_DEFAULT_HOST_URL, "/cgi-bin/menu/trymatch"),
     /**
      * get.
      */
-    MENU_GET(WX_API_BASE_URL, "/cgi-bin/menu/get"),
+    MENU_GET(API_DEFAULT_HOST_URL, "/cgi-bin/menu/get"),
     /**
      * delconditional.
      */
-    MENU_DELCONDITIONAL(WX_API_BASE_URL, "/cgi-bin/menu/delconditional"),
+    MENU_DELCONDITIONAL(API_DEFAULT_HOST_URL, "/cgi-bin/menu/delconditional"),
     /**
      * delete.
      */
-    MENU_DELETE(WX_API_BASE_URL, "/cgi-bin/menu/delete"),
+    MENU_DELETE(API_DEFAULT_HOST_URL, "/cgi-bin/menu/delete"),
     /**
      * create.
      */
-    MENU_CREATE(WX_API_BASE_URL, "/cgi-bin/menu/create"),
+    MENU_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/menu/create"),
     /**
      * addconditional.
      */
-    MENU_ADDCONDITIONAL(WX_API_BASE_URL, "/cgi-bin/menu/addconditional");
+    MENU_ADDCONDITIONAL(API_DEFAULT_HOST_URL, "/cgi-bin/menu/addconditional");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -209,22 +210,22 @@ public interface WxMpApiUrl {
     /**
      * create.
      */
-    QRCODE_CREATE(WX_API_BASE_URL, "/cgi-bin/qrcode/create"),
+    QRCODE_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/qrcode/create"),
     /**
      * showqrcode.
      */
-    SHOW_QRCODE(WX_MP_BASE_URL, "/cgi-bin/showqrcode"),
+    SHOW_QRCODE(MP_DEFAULT_HOST_URL, "/cgi-bin/showqrcode"),
     /**
      * showqrcode.
      */
-    SHOW_QRCODE_WITH_TICKET(WX_MP_BASE_URL, "/cgi-bin/showqrcode?ticket=%s");
+    SHOW_QRCODE_WITH_TICKET(MP_DEFAULT_HOST_URL, "/cgi-bin/showqrcode?ticket=%s");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -233,27 +234,26 @@ public interface WxMpApiUrl {
     /**
      * getshakeinfo.
      */
-    SHAKEAROUND_USER_GETSHAKEINFO(WX_API_BASE_URL, "/shakearound/user/getshakeinfo"),
+    SHAKEAROUND_USER_GETSHAKEINFO(API_DEFAULT_HOST_URL, "/shakearound/user/getshakeinfo"),
     /**
      * add.
      */
-    SHAKEAROUND_PAGE_ADD(WX_API_BASE_URL, "/shakearound/page/add"),
+    SHAKEAROUND_PAGE_ADD(API_DEFAULT_HOST_URL, "/shakearound/page/add"),
     /**
      * bindpage.
      */
-    SHAKEAROUND_DEVICE_BINDPAGE(WX_API_BASE_URL, "/shakearound/device/bindpage"),
+    SHAKEAROUND_DEVICE_BINDPAGE(API_DEFAULT_HOST_URL, "/shakearound/device/bindpage"),
     /**
      * search.
      */
-    SHAKEAROUND_RELATION_SEARCH(WX_API_BASE_URL, "/shakearound/relation/search");
-
+    SHAKEAROUND_RELATION_SEARCH(API_DEFAULT_HOST_URL, "/shakearound/relation/search");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -262,18 +262,18 @@ public interface WxMpApiUrl {
     /**
      * subscribemsg.
      */
-    SUBSCRIBE_MESSAGE_AUTHORIZE_URL(WX_MP_BASE_URL, "/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect"),
+    SUBSCRIBE_MESSAGE_AUTHORIZE_URL(MP_DEFAULT_HOST_URL, "/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect"),
     /**
      * subscribe.
      */
-    SEND_MESSAGE_URL(WX_API_BASE_URL, "/cgi-bin/message/template/subscribe");
+    SEND_MESSAGE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/template/subscribe");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -282,34 +282,34 @@ public interface WxMpApiUrl {
     /**
      * send.
      */
-    MESSAGE_TEMPLATE_SEND(WX_API_BASE_URL, "/cgi-bin/message/template/send"),
+    MESSAGE_TEMPLATE_SEND(API_DEFAULT_HOST_URL, "/cgi-bin/message/template/send"),
     /**
      * api_set_industry.
      */
-    TEMPLATE_API_SET_INDUSTRY(WX_API_BASE_URL, "/cgi-bin/template/api_set_industry"),
+    TEMPLATE_API_SET_INDUSTRY(API_DEFAULT_HOST_URL, "/cgi-bin/template/api_set_industry"),
     /**
      * get_industry.
      */
-    TEMPLATE_GET_INDUSTRY(WX_API_BASE_URL, "/cgi-bin/template/get_industry"),
+    TEMPLATE_GET_INDUSTRY(API_DEFAULT_HOST_URL, "/cgi-bin/template/get_industry"),
     /**
      * api_add_template.
      */
-    TEMPLATE_API_ADD_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/api_add_template"),
+    TEMPLATE_API_ADD_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/api_add_template"),
     /**
      * get_all_private_template.
      */
-    TEMPLATE_GET_ALL_PRIVATE_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/get_all_private_template"),
+    TEMPLATE_GET_ALL_PRIVATE_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/get_all_private_template"),
     /**
      * del_private_template.
      */
-    TEMPLATE_DEL_PRIVATE_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/del_private_template");
+    TEMPLATE_DEL_PRIVATE_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/del_private_template");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -318,22 +318,22 @@ public interface WxMpApiUrl {
     /**
      * getblacklist.
      */
-    GETBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/getblacklist"),
+    GETBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/getblacklist"),
     /**
      * batchblacklist.
      */
-    BATCHBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/batchblacklist"),
+    BATCHBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchblacklist"),
     /**
      * batchunblacklist.
      */
-    BATCHUNBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/batchunblacklist");
+    BATCHUNBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchunblacklist");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -342,42 +342,42 @@ public interface WxMpApiUrl {
     /**
      * create.
      */
-    TAGS_CREATE(WX_API_BASE_URL, "/cgi-bin/tags/create"),
+    TAGS_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/create"),
     /**
      * get.
      */
-    TAGS_GET(WX_API_BASE_URL, "/cgi-bin/tags/get"),
+    TAGS_GET(API_DEFAULT_HOST_URL, "/cgi-bin/tags/get"),
     /**
      * update.
      */
-    TAGS_UPDATE(WX_API_BASE_URL, "/cgi-bin/tags/update"),
+    TAGS_UPDATE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/update"),
     /**
      * delete.
      */
-    TAGS_DELETE(WX_API_BASE_URL, "/cgi-bin/tags/delete"),
+    TAGS_DELETE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/delete"),
     /**
      * get.
      */
-    TAG_GET(WX_API_BASE_URL, "/cgi-bin/user/tag/get"),
+    TAG_GET(API_DEFAULT_HOST_URL, "/cgi-bin/user/tag/get"),
     /**
      * batchtagging.
      */
-    TAGS_MEMBERS_BATCHTAGGING(WX_API_BASE_URL, "/cgi-bin/tags/members/batchtagging"),
+    TAGS_MEMBERS_BATCHTAGGING(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchtagging"),
     /**
      * batchuntagging.
      */
-    TAGS_MEMBERS_BATCHUNTAGGING(WX_API_BASE_URL, "/cgi-bin/tags/members/batchuntagging"),
+    TAGS_MEMBERS_BATCHUNTAGGING(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchuntagging"),
     /**
      * getidlist.
      */
-    TAGS_GETIDLIST(WX_API_BASE_URL, "/cgi-bin/tags/getidlist");
+    TAGS_GETIDLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/getidlist");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -386,14 +386,14 @@ public interface WxMpApiUrl {
     /**
      * list.
      */
-    BIZWIFI_SHOP_LIST(WX_API_BASE_URL, "/bizwifi/shop/list");
+    BIZWIFI_SHOP_LIST(API_DEFAULT_HOST_URL, "/bizwifi/shop/list");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -402,22 +402,22 @@ public interface WxMpApiUrl {
     /**
      * translatecontent.
      */
-    TRANSLATE_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/translatecontent?lfrom=%s<o=%s"),
+    TRANSLATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/translatecontent?lfrom=%s<o=%s"),
     /**
      * addvoicetorecofortext.
      */
-    VOICE_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/addvoicetorecofortext?format=%s&voice_id=%s&lang=%s"),
+    VOICE_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/addvoicetorecofortext?format=%s&voice_id=%s&lang=%s"),
     /**
      * queryrecoresultfortext.
      */
-    VOICE_QUERY_RESULT_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/queryrecoresultfortext");
+    VOICE_QUERY_RESULT_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/queryrecoresultfortext");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -426,58 +426,58 @@ public interface WxMpApiUrl {
     /**
      * create.
      */
-    CARD_CREATE(WX_API_BASE_URL, "/card/create"),
+    CARD_CREATE(API_DEFAULT_HOST_URL, "/card/create"),
     /**
      * get.
      */
-    CARD_GET(WX_API_BASE_URL, "/card/get"),
+    CARD_GET(API_DEFAULT_HOST_URL, "/card/get"),
     /**
      * wx_card.
      */
-    CARD_GET_TICKET(WX_API_BASE_URL, "/cgi-bin/ticket/getticket?type=wx_card"),
+    CARD_GET_TICKET(API_DEFAULT_HOST_URL, "/cgi-bin/ticket/getticket?type=wx_card"),
     /**
      * decrypt.
      */
-    CARD_CODE_DECRYPT(WX_API_BASE_URL, "/card/code/decrypt"),
+    CARD_CODE_DECRYPT(API_DEFAULT_HOST_URL, "/card/code/decrypt"),
     /**
      * get.
      */
-    CARD_CODE_GET(WX_API_BASE_URL, "/card/code/get"),
+    CARD_CODE_GET(API_DEFAULT_HOST_URL, "/card/code/get"),
     /**
      * consume.
      */
-    CARD_CODE_CONSUME(WX_API_BASE_URL, "/card/code/consume"),
+    CARD_CODE_CONSUME(API_DEFAULT_HOST_URL, "/card/code/consume"),
     /**
      * mark.
      */
-    CARD_CODE_MARK(WX_API_BASE_URL, "/card/code/mark"),
+    CARD_CODE_MARK(API_DEFAULT_HOST_URL, "/card/code/mark"),
     /**
      * set.
      */
-    CARD_TEST_WHITELIST(WX_API_BASE_URL, "/card/testwhitelist/set"),
+    CARD_TEST_WHITELIST(API_DEFAULT_HOST_URL, "/card/testwhitelist/set"),
     /**
      * create.
      */
-    CARD_QRCODE_CREATE(WX_API_BASE_URL, "/card/qrcode/create"),
+    CARD_QRCODE_CREATE(API_DEFAULT_HOST_URL, "/card/qrcode/create"),
     /**
      * create.
      */
-    CARD_LANDING_PAGE_CREATE(WX_API_BASE_URL, "/card/landingpage/create"),
+    CARD_LANDING_PAGE_CREATE(API_DEFAULT_HOST_URL, "/card/landingpage/create"),
     /**
      * 将用户的卡券设置为失效状态.
      */
-    CARD_CODE_UNAVAILABLE(WX_API_BASE_URL, "/card/code/unavailable"),
+    CARD_CODE_UNAVAILABLE(API_DEFAULT_HOST_URL, "/card/code/unavailable"),
     /**
      * 卡券删除.
      */
-    CARD_DELETE(WX_API_BASE_URL, "/card/delete");
+    CARD_DELETE(API_DEFAULT_HOST_URL, "/card/delete");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -486,78 +486,78 @@ public interface WxMpApiUrl {
     /**
      * getusersummary.
      */
-    GET_USER_SUMMARY(WX_API_BASE_URL, "/datacube/getusersummary"),
+    GET_USER_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getusersummary"),
     /**
      * getusercumulate.
      */
-    GET_USER_CUMULATE(WX_API_BASE_URL, "/datacube/getusercumulate"),
+    GET_USER_CUMULATE(API_DEFAULT_HOST_URL, "/datacube/getusercumulate"),
     /**
      * getarticlesummary.
      */
-    GET_ARTICLE_SUMMARY(WX_API_BASE_URL, "/datacube/getarticlesummary"),
+    GET_ARTICLE_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getarticlesummary"),
     /**
      * getarticletotal.
      */
-    GET_ARTICLE_TOTAL(WX_API_BASE_URL, "/datacube/getarticletotal"),
+    GET_ARTICLE_TOTAL(API_DEFAULT_HOST_URL, "/datacube/getarticletotal"),
     /**
      * getuserread.
      */
-    GET_USER_READ(WX_API_BASE_URL, "/datacube/getuserread"),
+    GET_USER_READ(API_DEFAULT_HOST_URL, "/datacube/getuserread"),
     /**
      * getuserreadhour.
      */
-    GET_USER_READ_HOUR(WX_API_BASE_URL, "/datacube/getuserreadhour"),
+    GET_USER_READ_HOUR(API_DEFAULT_HOST_URL, "/datacube/getuserreadhour"),
     /**
      * getusershare.
      */
-    GET_USER_SHARE(WX_API_BASE_URL, "/datacube/getusershare"),
+    GET_USER_SHARE(API_DEFAULT_HOST_URL, "/datacube/getusershare"),
     /**
      * getusersharehour.
      */
-    GET_USER_SHARE_HOUR(WX_API_BASE_URL, "/datacube/getusersharehour"),
+    GET_USER_SHARE_HOUR(API_DEFAULT_HOST_URL, "/datacube/getusersharehour"),
     /**
      * getupstreammsg.
      */
-    GET_UPSTREAM_MSG(WX_API_BASE_URL, "/datacube/getupstreammsg"),
+    GET_UPSTREAM_MSG(API_DEFAULT_HOST_URL, "/datacube/getupstreammsg"),
     /**
      * getupstreammsghour.
      */
-    GET_UPSTREAM_MSG_HOUR(WX_API_BASE_URL, "/datacube/getupstreammsghour"),
+    GET_UPSTREAM_MSG_HOUR(API_DEFAULT_HOST_URL, "/datacube/getupstreammsghour"),
     /**
      * getupstreammsgweek.
      */
-    GET_UPSTREAM_MSG_WEEK(WX_API_BASE_URL, "/datacube/getupstreammsgweek"),
+    GET_UPSTREAM_MSG_WEEK(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgweek"),
     /**
      * getupstreammsgmonth.
      */
-    GET_UPSTREAM_MSG_MONTH(WX_API_BASE_URL, "/datacube/getupstreammsgmonth"),
+    GET_UPSTREAM_MSG_MONTH(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgmonth"),
     /**
      * getupstreammsgdist.
      */
-    GET_UPSTREAM_MSG_DIST(WX_API_BASE_URL, "/datacube/getupstreammsgdist"),
+    GET_UPSTREAM_MSG_DIST(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdist"),
     /**
      * getupstreammsgdistweek.
      */
-    GET_UPSTREAM_MSG_DIST_WEEK(WX_API_BASE_URL, "/datacube/getupstreammsgdistweek"),
+    GET_UPSTREAM_MSG_DIST_WEEK(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdistweek"),
     /**
      * getupstreammsgdistmonth.
      */
-    GET_UPSTREAM_MSG_DIST_MONTH(WX_API_BASE_URL, "/datacube/getupstreammsgdistmonth"),
+    GET_UPSTREAM_MSG_DIST_MONTH(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdistmonth"),
     /**
      * getinterfacesummary.
      */
-    GET_INTERFACE_SUMMARY(WX_API_BASE_URL, "/datacube/getinterfacesummary"),
+    GET_INTERFACE_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getinterfacesummary"),
     /**
      * getinterfacesummaryhour.
      */
-    GET_INTERFACE_SUMMARY_HOUR(WX_API_BASE_URL, "/datacube/getinterfacesummaryhour");
+    GET_INTERFACE_SUMMARY_HOUR(API_DEFAULT_HOST_URL, "/datacube/getinterfacesummaryhour");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -566,70 +566,70 @@ public interface WxMpApiUrl {
     /**
      * send.
      */
-    MESSAGE_CUSTOM_SEND(WX_API_BASE_URL, "/cgi-bin/message/custom/send"),
+    MESSAGE_CUSTOM_SEND(API_DEFAULT_HOST_URL, "/cgi-bin/message/custom/send"),
     /**
      * getkflist.
      */
-    GET_KF_LIST(WX_API_BASE_URL, "/cgi-bin/customservice/getkflist"),
+    GET_KF_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/customservice/getkflist"),
     /**
      * getonlinekflist.
      */
-    GET_ONLINE_KF_LIST(WX_API_BASE_URL, "/cgi-bin/customservice/getonlinekflist"),
+    GET_ONLINE_KF_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/customservice/getonlinekflist"),
     /**
      * add.
      */
-    KFACCOUNT_ADD(WX_API_BASE_URL, "/customservice/kfaccount/add"),
+    KFACCOUNT_ADD(API_DEFAULT_HOST_URL, "/customservice/kfaccount/add"),
     /**
      * update.
      */
-    KFACCOUNT_UPDATE(WX_API_BASE_URL, "/customservice/kfaccount/update"),
+    KFACCOUNT_UPDATE(API_DEFAULT_HOST_URL, "/customservice/kfaccount/update"),
     /**
      * inviteworker.
      */
-    KFACCOUNT_INVITE_WORKER(WX_API_BASE_URL, "/customservice/kfaccount/inviteworker"),
+    KFACCOUNT_INVITE_WORKER(API_DEFAULT_HOST_URL, "/customservice/kfaccount/inviteworker"),
     /**
      * uploadheadimg.
      */
-    KFACCOUNT_UPLOAD_HEAD_IMG(WX_API_BASE_URL, "/customservice/kfaccount/uploadheadimg?kf_account=%s"),
+    KFACCOUNT_UPLOAD_HEAD_IMG(API_DEFAULT_HOST_URL, "/customservice/kfaccount/uploadheadimg?kf_account=%s"),
     /**
      * del kfaccount.
      */
-    KFACCOUNT_DEL(WX_API_BASE_URL, "/customservice/kfaccount/del?kf_account=%s"),
+    KFACCOUNT_DEL(API_DEFAULT_HOST_URL, "/customservice/kfaccount/del?kf_account=%s"),
     /**
      * create.
      */
-    KFSESSION_CREATE(WX_API_BASE_URL, "/customservice/kfsession/create"),
+    KFSESSION_CREATE(API_DEFAULT_HOST_URL, "/customservice/kfsession/create"),
     /**
      * close.
      */
-    KFSESSION_CLOSE(WX_API_BASE_URL, "/customservice/kfsession/close"),
+    KFSESSION_CLOSE(API_DEFAULT_HOST_URL, "/customservice/kfsession/close"),
     /**
      * getsession.
      */
-    KFSESSION_GET_SESSION(WX_API_BASE_URL, "/customservice/kfsession/getsession?openid=%s"),
+    KFSESSION_GET_SESSION(API_DEFAULT_HOST_URL, "/customservice/kfsession/getsession?openid=%s"),
     /**
      * getsessionlist.
      */
-    KFSESSION_GET_SESSION_LIST(WX_API_BASE_URL, "/customservice/kfsession/getsessionlist?kf_account=%s"),
+    KFSESSION_GET_SESSION_LIST(API_DEFAULT_HOST_URL, "/customservice/kfsession/getsessionlist?kf_account=%s"),
     /**
      * getwaitcase.
      */
-    KFSESSION_GET_WAIT_CASE(WX_API_BASE_URL, "/customservice/kfsession/getwaitcase"),
+    KFSESSION_GET_WAIT_CASE(API_DEFAULT_HOST_URL, "/customservice/kfsession/getwaitcase"),
     /**
      * getmsglist.
      */
-    MSG_RECORD_LIST(WX_API_BASE_URL, "/customservice/msgrecord/getmsglist"),
+    MSG_RECORD_LIST(API_DEFAULT_HOST_URL, "/customservice/msgrecord/getmsglist"),
     /**
      * typing.
      */
-    CUSTOM_TYPING(WX_API_BASE_URL, "/cgi-bin/message/custom/typing");
+    CUSTOM_TYPING(API_DEFAULT_HOST_URL, "/cgi-bin/message/custom/typing");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -638,34 +638,34 @@ public interface WxMpApiUrl {
     /**
      * 上传群发用的图文消息.
      */
-    MEDIA_UPLOAD_NEWS_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadnews"),
+    MEDIA_UPLOAD_NEWS_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadnews"),
     /**
      * 上传群发用的视频.
      */
-    MEDIA_UPLOAD_VIDEO_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadvideo"),
+    MEDIA_UPLOAD_VIDEO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadvideo"),
     /**
      * 分组群发消息.
      */
-    MESSAGE_MASS_SENDALL_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/sendall"),
+    MESSAGE_MASS_SENDALL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/sendall"),
     /**
      * 按openId列表群发消息.
      */
-    MESSAGE_MASS_SEND_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/send"),
+    MESSAGE_MASS_SEND_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/send"),
     /**
      * 群发消息预览接口.
      */
-    MESSAGE_MASS_PREVIEW_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/preview"),
+    MESSAGE_MASS_PREVIEW_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/preview"),
     /**
      * 删除群发接口.
      */
-    MESSAGE_MASS_DELETE_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/delete");
+    MESSAGE_MASS_DELETE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/delete");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -674,50 +674,50 @@ public interface WxMpApiUrl {
     /**
      * get.
      */
-    MEDIA_GET_URL(WX_API_BASE_URL, "/cgi-bin/media/get"),
+    MEDIA_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/get"),
     /**
      * upload.
      */
-    MEDIA_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/upload?type=%s"),
+    MEDIA_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/upload?type=%s"),
     /**
      * uploadimg.
      */
-    IMG_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadimg"),
+    IMG_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadimg"),
     /**
      * add_material.
      */
-    MATERIAL_ADD_URL(WX_API_BASE_URL, "/cgi-bin/material/add_material?type=%s"),
+    MATERIAL_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/add_material?type=%s"),
     /**
      * add_news.
      */
-    NEWS_ADD_URL(WX_API_BASE_URL, "/cgi-bin/material/add_news"),
+    NEWS_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/add_news"),
     /**
      * get_material.
      */
-    MATERIAL_GET_URL(WX_API_BASE_URL, "/cgi-bin/material/get_material"),
+    MATERIAL_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/get_material"),
     /**
      * update_news.
      */
-    NEWS_UPDATE_URL(WX_API_BASE_URL, "/cgi-bin/material/update_news"),
+    NEWS_UPDATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/update_news"),
     /**
      * del_material.
      */
-    MATERIAL_DEL_URL(WX_API_BASE_URL, "/cgi-bin/material/del_material"),
+    MATERIAL_DEL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/del_material"),
     /**
      * get_materialcount.
      */
-    MATERIAL_GET_COUNT_URL(WX_API_BASE_URL, "/cgi-bin/material/get_materialcount"),
+    MATERIAL_GET_COUNT_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/get_materialcount"),
     /**
      * batchget_material.
      */
-    MATERIAL_BATCHGET_URL(WX_API_BASE_URL, "/cgi-bin/material/batchget_material");
+    MATERIAL_BATCHGET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/batchget_material");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -726,43 +726,43 @@ public interface WxMpApiUrl {
     /**
      * create.
      */
-    MEMBER_CARD_CREATE(WX_API_BASE_URL, "/card/create"),
+    MEMBER_CARD_CREATE(API_DEFAULT_HOST_URL, "/card/create"),
     /**
      * activate.
      */
-    MEMBER_CARD_ACTIVATE(WX_API_BASE_URL, "/card/membercard/activate"),
+    MEMBER_CARD_ACTIVATE(API_DEFAULT_HOST_URL, "/card/membercard/activate"),
     /**
      * get userinfo.
      */
-    MEMBER_CARD_USER_INFO_GET(WX_API_BASE_URL, "/card/membercard/userinfo/get"),
+    MEMBER_CARD_USER_INFO_GET(API_DEFAULT_HOST_URL, "/card/membercard/userinfo/get"),
     /**
      * updateuser.
      */
-    MEMBER_CARD_UPDATE_USER(WX_API_BASE_URL, "/card/membercard/updateuser"),
+    MEMBER_CARD_UPDATE_USER(API_DEFAULT_HOST_URL, "/card/membercard/updateuser"),
     /**
      * 会员卡激活之微信开卡接口(wx_activate=true情况调用).
      */
-    MEMBER_CARD_ACTIVATE_USER_FORM(WX_API_BASE_URL, "/card/membercard/activateuserform/set"),
+    MEMBER_CARD_ACTIVATE_USER_FORM(API_DEFAULT_HOST_URL, "/card/membercard/activateuserform/set"),
     /**
      * 获取会员卡开卡插件参数.
      */
-    MEMBER_CARD_ACTIVATE_URL(WX_API_BASE_URL, "/card/membercard/activate/geturl"),
+    MEMBER_CARD_ACTIVATE_URL(API_DEFAULT_HOST_URL, "/card/membercard/activate/geturl"),
     /**
      * 会员卡信息更新.
      */
-    MEMBER_CARD_UPDATE(WX_API_BASE_URL, "/card/update"),
+    MEMBER_CARD_UPDATE(API_DEFAULT_HOST_URL, "/card/update"),
     /**
      * 跳转型会员卡开卡字段.
      * 获取用户提交资料(wx_activate=true情况调用),开发者根据activate_ticket获取到用户填写的信息
      */
-    MEMBER_CARD_ACTIVATE_TEMP_INFO(WX_API_BASE_URL, "/card/membercard/activatetempinfo/get");
+    MEMBER_CARD_ACTIVATE_TEMP_INFO(API_DEFAULT_HOST_URL, "/card/membercard/activatetempinfo/get");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -771,34 +771,34 @@ public interface WxMpApiUrl {
     /**
      * getwxcategory.
      */
-    POI_GET_WX_CATEGORY_URL(WX_API_BASE_URL, "/cgi-bin/poi/getwxcategory"),
+    POI_GET_WX_CATEGORY_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getwxcategory"),
     /**
      * updatepoi.
      */
-    POI_UPDATE_URL(WX_API_BASE_URL, "/cgi-bin/poi/updatepoi"),
+    POI_UPDATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/updatepoi"),
     /**
      * getpoilist.
      */
-    POI_LIST_URL(WX_API_BASE_URL, "/cgi-bin/poi/getpoilist"),
+    POI_LIST_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getpoilist"),
     /**
      * delpoi.
      */
-    POI_DEL_URL(WX_API_BASE_URL, "/cgi-bin/poi/delpoi"),
+    POI_DEL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/delpoi"),
     /**
      * getpoi.
      */
-    POI_GET_URL(WX_API_BASE_URL, "/cgi-bin/poi/getpoi"),
+    POI_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getpoi"),
     /**
      * addpoi.
      */
-    POI_ADD_URL(WX_API_BASE_URL, "/cgi-bin/poi/addpoi");
+    POI_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/addpoi");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -808,30 +808,30 @@ public interface WxMpApiUrl {
     /**
      * batchget.
      */
-    USER_INFO_BATCH_GET_URL(WX_API_BASE_URL, "/cgi-bin/user/info/batchget"),
+    USER_INFO_BATCH_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info/batchget"),
     /**
      * get.
      */
-    USER_GET_URL(WX_API_BASE_URL, "/cgi-bin/user/get"),
+    USER_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/get"),
     /**
      * info.
      */
-    USER_INFO_URL(WX_API_BASE_URL, "/cgi-bin/user/info"),
+    USER_INFO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info"),
     /**
      * updateremark.
      */
-    USER_INFO_UPDATE_REMARK_URL(WX_API_BASE_URL, "/cgi-bin/user/info/updateremark"),
+    USER_INFO_UPDATE_REMARK_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info/updateremark"),
     /**
      * changeopenid.
      */
-    USER_CHANGE_OPENID_URL(WX_API_BASE_URL, "/cgi-bin/changeopenid");
+    USER_CHANGE_OPENID_URL(API_DEFAULT_HOST_URL, "/cgi-bin/changeopenid");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java
index b16775b4..1d1ae909 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java
@@ -17,6 +17,9 @@ import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage;
 import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry;
 import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
 
+/**
+ * @author someone
+ */
 public class WxMpGsonBuilder {
 
   private static final GsonBuilder INSTANCE = new GsonBuilder();
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
index da34e808..ef699212 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
@@ -11,6 +11,7 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.mp.api.WxMpConfigStorage;
+import me.chanjar.weixin.mp.bean.WxMpHostConfig;
 import me.chanjar.weixin.mp.enums.TicketType;
 import me.chanjar.weixin.open.api.WxOpenConfigStorage;
 import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken;
@@ -543,10 +544,14 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
       return wxOpenConfigStorage.getApacheHttpClientBuilder();
     }
 
-
     @Override
     public boolean autoRefreshToken() {
       return true;
     }
+
+    @Override
+    public WxMpHostConfig getHostConfig() {
+      return null;
+    }
   }
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
index a946fb70..104215bb 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
@@ -9,7 +9,7 @@ import me.chanjar.weixin.open.api.WxOpenComponentService;
 /**
  * @author 007
  */
-/* package */ class WxOpenMpServiceImpl extends WxMpServiceImpl {
+/* package(无需对外暴露) */ class WxOpenMpServiceImpl extends WxMpServiceImpl {
   private WxOpenComponentService wxOpenComponentService;
   private WxMpConfigStorage wxMpConfigStorage;
   private String appId;