Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openapi请求如果key是a.bS/TT/AT,则报404错误 #4447

Closed
PeterHang opened this issue Jul 6, 2022 · 19 comments · Fixed by #4549
Closed

openapi请求如果key是a.bS/TT/AT,则报404错误 #4447

PeterHang opened this issue Jul 6, 2022 · 19 comments · Fixed by #4549

Comments

@PeterHang
Copy link

PeterHang commented Jul 6, 2022

openapi的Java client,1.7.0,如果key是a.bS/TT/AT,则请求就会报404错误。上次修完后,[]是可以了,但是key为a.bS/TT/AT还是不行,只不过这次报404了

@CalebZYC
Copy link
Contributor

CalebZYC commented Jul 6, 2022

tomcat路径中允许未编码的字符和查询字符串中允许的未编码字符,/字符不在范围内

" < > [ \ ] ^ ` { | }

image
tomcat attribute

@PeterHang
Copy link
Author

那这就比较尴尬了,在网页上操作是允许放 / 字符的,在openapi就不行了,那应该怎么办?
总不能因为网页上key是放在body里面,openapi的key是在url里面,然后有些key的字符在open api就不支持,对吧?

@PeterHang
Copy link
Author

tomcat路径中允许未编码的字符和查询字符串中允许的未编码字符,/字符不在范围内

" < > [ \ ] ^ ` { | }

image tomcat attribute

那这就比较尴尬了,在网页上操作是允许放 / 字符的,在openapi就不行了,那应该怎么办?
总不能因为网页上key是放在body里面,openapi的key是在url里面,然后有些key的字符在open api就不支持,对吧?

@qmwu2000
Copy link
Collaborator

qmwu2000 commented Jul 11, 2022 via email

@PeterHang
Copy link
Author

PeterHang commented Jul 11, 2022

tomcat具体支持哪些字符不重要,重要的是所有客户端必须严格按照HTTP协议规定的格式发送请求,该怎么编码就怎么编码,不能与具体哪一个web container绑定。

image
那现在可以在网页上保存key里面含有“/”字符,用Apollo open api的Java client 应该请求?

@PeterHang PeterHang reopened this Jul 11, 2022
@PeterHang
Copy link
Author

tomcat具体支持哪些字符不重要,重要的是所有客户端必须严格按照HTTP协议规定的格式发送请求,该怎么编码就怎么编码,不能与具体哪一个web container绑定。

On Jul 8, 2022, at 11:13, PeterHang @.***> wrote: tomcat路径中允许未编码的字符和查询字符串中允许的未编码字符,/字符不在范围内 " < > [ \ ] ^ ` { | } https://user-images.githubusercontent.com/42887532/177584445-a2450cce-999c-44bd-8ce1-a249335a73c7.png tomcat attribute https://tomcat.apache.org/tomcat-8.5-doc/config/http.html 那这就比较尴尬了,在网页上操作是允许放 / 字符的,在openapi就不行了,那应该怎么办? 总不能因为网页上key是放在body里面,openapi的key是在url里面,然后有些key的字符在open api就不支持,对吧? — Reply to this email directly, view it on GitHub <#4447 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AASQE76E63SX7N76INUPDILVS6MEPANCNFSM52YHMFWA. You are receiving this because you are subscribed to this thread.

image
那现在可以在网页上保存key里面含有“/”字符,用Apollo open api的Java client 应该请求?

@nobodyiam
Copy link
Member

那现在可以在网页上保存key里面含有“/”字符,用Apollo open api的Java client 应该请求?

造成这个差异的原因是通过页面修改/删除配置的接口没有把 key 放在 url path 上,而 open api 的实现是把 key 放在 url path 上的。
updateItem 可以比较简单的适配一下,比如新开一个不带 key 的接口。
deleteItem 的适配就要麻烦一点了,因为 openapi 现在的 dto 没有把 item id 返回给调用端,这个得看下实现方案。

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@PutMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item")
public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@RequestBody ItemDTO item) {

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env) ")
@DeleteMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items/{itemId}")
public void deleteItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable long itemId) {

@PreAuthorize(value = "@consumerPermissionValidator.hasModifyNamespacePermission(#request, #appId, #namespaceName, #env)")
@PutMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key:.+}")
public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable String key, @RequestBody OpenItemDTO item,
@RequestParam(defaultValue = "false") boolean createIfNotExists, HttpServletRequest request) {

@PreAuthorize(value = "@consumerPermissionValidator.hasModifyNamespacePermission(#request, #appId, #namespaceName, #env)")
@DeleteMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key:.+}")
public void deleteItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable String key, @RequestParam String operator,
HttpServletRequest request) {

@PeterHang
Copy link
Author

那现在可以在网页上保存key里面含有“/”字符,用Apollo open api的Java client 应该请求?

造成这个差异的原因是通过页面修改/删除配置的接口没有把 key 放在 url path 上,而 open api 的实现是把 key 放在 url path 上的。 updateItem 可以比较简单的适配一下,比如新开一个不带 key 的接口。 deleteItem 的适配就要麻烦一点了,因为 openapi 现在的 dto 没有把 item id 返回给调用端,这个得看下实现方案。

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@PutMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item")
public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@RequestBody ItemDTO item) {

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env) ")
@DeleteMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items/{itemId}")
public void deleteItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable long itemId) {

@PreAuthorize(value = "@consumerPermissionValidator.hasModifyNamespacePermission(#request, #appId, #namespaceName, #env)")
@PutMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key:.+}")
public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable String key, @RequestBody OpenItemDTO item,
@RequestParam(defaultValue = "false") boolean createIfNotExists, HttpServletRequest request) {

@PreAuthorize(value = "@consumerPermissionValidator.hasModifyNamespacePermission(#request, #appId, #namespaceName, #env)")
@DeleteMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key:.+}")
public void deleteItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable String key, @RequestParam String operator,
HttpServletRequest request) {

image
本地试了下,如果改的话,admin service也得改。查询item的话,还是将key放在URL上去查询的。

@nobodyiam
Copy link
Member

@PeterHang 是的,更新还好搞一些,PUT 操作可以把 item key 放在 body 里面,查询和删除这两个操作比较麻烦,GET 和 DELETE 只能放在 url path 上

@AbnerHuang2
Copy link
Contributor

是的,更新还好搞一些,PUT 操作可以把 item key 放在 body 里面,查询和删除这两个操作比较麻烦,GET 和 DELETE 只能放在 url path 上

what if we just encode/decode the item key ? we can provide new interface on get/update/delete , and we encode the item key in client and decode key in admin service. in this way , the old client can also work normally. what do you think ? @nobodyiam

@snowy861227
Copy link

有什么进展吗?考虑更新支持key中带/的openapi更新吗?

@nobodyiam
Copy link
Member

what if we just encode/decode the item key ? we can provide new interface on get/update/delete , and we encode the item key in client and decode key in admin service. in this way , the old client can also work normally. what do you think ?

@AbnerHuang2 I'm interested in this proposal, would you please give an example to show your idea?

@AbnerHuang2
Copy link
Contributor

take getItem as an example, when we called getItem with openapi client, we can encode the key like the follow way,

    String encode = new String(Base64.getEncoder().encode(key.getBytes(StandardCharsets.UTF_8)));
    OpenApiPathBuilder pathBuilder = OpenApiPathBuilder.newBuilder()
        .envsPathVal(env)
        .appsPathVal(appId)
        .clustersPathVal(clusterName)
        .namespacesPathVal(namespaceName)
        .itemsPathVal(encode);

and this will execute in portal/ItemOpenController, and in this controller passthrough the key to adminservice/ItemController, and in adminservice/ItemController we decode the key like follow way,

key = new String(Base64.getDecoder().decode(key.getBytes(StandardCharsets.UTF_8)));
Item item = itemService.findOne(appId, clusterName, namespaceName, key);

then we can get the correct result.

ps, the encode/decode algorithm can be replace with other simple algorithm if their is more effective encode/decode algorithm.
@nobodyiam

@AbnerHuang2
Copy link
Contributor

Test example:

企业微信截图_1c35ab62-226e-4344-8a13-ff877a257e5e

Test Result:

企业微信截图_37a85783-b41c-4fbd-a744-26ea074f5959

@nobodyiam
Copy link
Member

@AbnerHuang2

This is an interesting proposal! In this way, we could add a new set of open apis that accept encoded keys.
I think we may still call the old set of apis if the key has no special character to make the apollo-openapi-client compatible with the old versions of apollo-portal.

@AbnerHuang2
Copy link
Contributor

wow, this way is more practicable, in the normal sutuation, it works like the old workflow, and we just use little cost to deal with unexpectable key, I'll try this. but I need to finished #4519 first.

@chenxing1020
Copy link

In my situation, I wrote a apollo portal http client, that also works.

@snowy861227
Copy link

snowy861227 commented Sep 16, 2022 via email

@nobodyiam
Copy link
Member

@snowy861227 This fix was merged to the master branch and not yet released.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants