时间:2023-02-26 12:24:01 | 来源:建站知识
时间:2023-02-26 12:24:01 来源:建站知识
cname记录是什么?他存在的意义是什么?:背景通过请求头传递租户标识是目前比较常见的方式,常见做法是在页面的登录页添加一个租户选择框,前端根据选择的租户标识在请求工具的拦截器统一带给后端。
该方式存在不足:
1.第三方对接支持不好,当该租户的接口需要给第三方做回调的时候就不能支持了,比如微信公众号回调、支付回调等。
2.对租户使用体验不好,需要租户自己在页面手动选择使用的租户,也不方便对登录页进行定制化设计。
一般作为通过请求头传递的一个补充,在不支持回调的情况下额外使用。
不建议使用,会和业务参数混合在一起,不方便区分。以上为常见的租户标识传递传递方案,通过请求头 + url 参数配合使用。今天小白给大家分享一个不一样的方案,通过域名 + CNAME 的方式传递租户标识。
*.tenant.xiaobai.com
映射到具体的ip
,这样就可以直接通过{租户标识}.tenant.xiaobai.com
访问到服务器,但是租户标识往往都是一些没有具体意义的一串字符,比如7e97639a733942c8ba530c5d54857a07
,加上大部分的租户都想使用自己的域名,需要增加租户自定义域名,这时候通过租户的域名 CNAME 解析到{租户标识}.tenant.xiaobai.com
DomainTenantParseUtils
/** * 解析域名租户 * * @param domain 当前访问域名 * @param tenantRootDomain 租户的根域名(可以是二级或者三级域名) * @return 租户标识 */ @Nullable public static String parseDomainTenant(@NonNull String domain, @NonNull String tenantRootDomain) { // ip不解析 if (IpUtils.isIP(domain)) { return null; } String resolvingResult; // 当前访问域名在租户根域名下解析结果为当前访问域名 if (domain.endsWith(tenantRootDomain)) { resolvingResult = domain; } else { resolvingResult = getResolvingResult(domain, Type.CNAME); } // 解析结果为空直接返回 if (Objects.isNull(resolvingResult)) { return null; } // 解析结果不在租户根域名下 if (!resolvingResult.endsWith(tenantRootDomain)) { return null; } String[] rootDomainArray = tenantRootDomain.split("//."); String[] resolvingResultArray = resolvingResult.split("//."); // 取租户根域名的下一级 if (resolvingResultArray.length > rootDomainArray.length) { return resolvingResultArray[resolvingResultArray.length - (rootDomainArray.length + 1)]; } return null; } /** * 获取域名解析结果 * * @param domain 域名 * @param type 类型 A记录 或者 CNAME * @see Type */ @Nullable public static String getResolvingResult(String domain, int type) { Resolver resolver; Lookup lookup; try { // 设置DNS服务器,这里使用常用的114.114.114.114 // TODO 这里也可做成配置化 resolver = new SimpleResolver("114.114.114.114"); lookup = new Lookup(domain, type); } catch (TextParseException | UnknownHostException e) { throw new RuntimeException("域名解析异常"); } lookup.setResolver(resolver); org.xbill.DNS.Cache cache = new org.xbill.DNS.Cache(); lookup.setCache(cache); lookup.run(); if (lookup.getResult() == Lookup.SUCCESSFUL) { String[] results = cache.toString().split("//n"); for (String result : results) { String rule = "(?<=//[)(.+?)(?=.])"; Pattern pattern = Pattern.compile(rule); Matcher matcher = pattern.matcher(result); if (matcher.find()) { return matcher.group(); } } } return null; }
TenantParseFilter
@Slf4j@RequiredArgsConstructorpublic class TenantParseFilter extends OncePerRequestFilter { private final TenantProperties tenantProperties; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String requestServerName = request.getServerName(); String tenant = DomainTenantParseUtils.parseDomainTenant(requestServerName, tenantProperties.getRootDomain()); if (!Objects.isNull(tenant)) { // 获取到了租户标识 if (log.isDebugEnabled()) { log.debug("域名解析到的租户标识:[{}]", tenant); } // TODO 写自己的业务操作,比如设置租户上下文传递 } filterChain.doFilter(request, response); }}
关键词:意义,记录