API
请求类型
POST
请求路径
/nacos/v1/ns/service
请求参数
名称 | 类型 | 是否必选 | 描述 |
---|---|---|---|
serviceName | 字符串 | 是 | 服务名 |
groupName | 字符串 | 否 | 分组名 |
namespaceId | 字符串 | 否 | 命名空间ID |
protectThreshold | 浮点数 | 否 | 保护阈值,取值0到1,默认0 |
metadata | 字符串 | 否 | 元数据 |
selector | JSON格式字符串 | 否 | 访问策略 |
错误编码
错误代码 | 描述 | 语义 |
---|---|---|
400 | Bad Request | 客户端请求中的语法错误 |
403 | Forbidden | 没有权限 |
404 | Not Found | 无法找到资源 |
500 | Internal Server Error | 服务器内部错误 |
200 | OK | 正常 |
示例请求
curl -X POST '127.0.0.1:8848/nacos/v1/ns/service?serviceName=nacos.test.2&metadata=k1%3dv1'
示例返回
ok
关键流程源码解析
ServiceController
/**
* Create a new service.
* 新建一个服务
* @param namespaceId namespace id
* @param serviceName service name
* @param protectThreshold protect threshold
* @param metadata service metadata
* @param selector selector
* @return 'ok' if success
* @throws Exception exception
*/
@PostMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String create(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,
@RequestParam String serviceName, @RequestParam(required = false, defaultValue = "0.0F") float protectThreshold,
@RequestParam(defaultValue = StringUtils.EMPTY) String metadata,
@RequestParam(defaultValue = StringUtils.EMPTY) String selector) throws Exception {
//检测是服务是否已创建
if (serviceManager.getService(namespaceId, serviceName) != null) {
throw new IllegalArgumentException("specified service already exists, serviceName : " + serviceName);
}
Map<String, String> metadataMap = new HashMap<>(16);
if (StringUtils.isNotBlank(metadata)) {
metadataMap = UtilsAndCommons.parseMetadata(metadata);
}
Service service = new Service(serviceName);
service.setProtectThreshold(protectThreshold);
service.setEnabled(true);
service.setMetadata(metadataMap);
//设置服务路由类型,默认为None,
//可以选择标签,并设置匹配规则 格式为:{"type": "label","expression": "CONSUMER.label.myLabel=PROVIDER.label.myLabel"}
service.setSelector(parseSelector(selector));
service.setNamespaceId(namespaceId);
service.setLastModifiedMillis(System.currentTimeMillis());
service.recalculateChecksum();
//服务名称以及集群规范性检查
service.validate();
//更新服务信息
serviceManager.addOrReplaceService(service);
return "ok";
}
private Selector parseSelector(String selectorJsonString) throws Exception {
//若传入的字符串为空,返回默认类型
if (StringUtils.isBlank(selectorJsonString)) {
return new NoneSelector();
}
//{type: "label", expression: "CONSUMER.label.site=PROVIDER.label.site"}
JsonNode selectorJson = JacksonUtils.toObj(URLDecoder.decode(selectorJsonString, "UTF-8"));
switch (SelectorType.valueOf(selectorJson.get("type").asText())) {
case none:
return new NoneSelector();
case label:
String expression = selectorJson.get("expression").asText();
//转化表达式标签,必须以CONSUMER.label.形式开始
Set<String> labels = LabelSelector.parseExpression(expression);
LabelSelector labelSelector = new LabelSelector();
labelSelector.setExpression(expression);
labelSelector.setLabels(labels);
return labelSelector;
default:
throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!");
}
}
总结
创建服务需要留意的地方就是服务路由类型可以选择标签模式,当选择标签时表达式必须以 CONSUMER.label. 开头,实际的标签可以自定义。可以结合自己公司的CMDB资源管理在查询实例列表时可以获取与表达式匹配的机房节点,该策略Nacos本身并没有实现,需要用户自己实现CmdbService配置匹配规则。具体实现此处不做描述。后续会专门写一篇案例实现。