Last active
February 1, 2021 15:19
-
-
Save jonenst/5afd4de92d716c37400dc1ed6883fa5d to your computer and use it in GitHub Desktop.
UriComponentsBuilder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
UriComponentsBuilder: | |
RESUME: REGLES D'OR | |
* toujours appeler encode(), même quand on encode pas (!!!!) (encode pas = build(true)) | |
* toujours utiliser toUri() plutôt que toUriString() | |
* (presque) toujours utiliser .encode().build(false).expand(vars).toUri() ou le raccourci build(vars) | |
Interaction avec restTemplateBuilder: | |
restTemplateBuilder utiliser le mode recommandé si on fait new DefaultUriBuilderFactory(baseUri), | |
mais dans ce cas oblige obligatoirememnt à utiliser un template... | |
Si on veut utiliser UriComponentBuilder explicitement, il faut absolument passer des URIs au lieu de strings à RestTemplate, | |
mais dans ce cas on perd la fonctionnalité de baseUri du templateHandler.. il faut récuperer le baseUri soit même. | |
Pour utiliser, il y a 3 modes: | |
modes recommandés: | |
.build(true) : safe, tout doit avoir été parfaitement encodé si besoin | |
(sinon exception), et si quelqu'un appelle encode() fait pas de double | |
encoding. Pas d'expand. | |
.encode().build(false).expand(vars) : safe, rien ne doit avoir été encodé (sinon double | |
encoding), mettre la structure de l'url dans la template et les données dans les variables. | |
encoding "minimal pour la template, encoding "maximal" pour les variables; | |
mode OK ~~: | |
build(false).encode() ou | |
build(false).encode().expand(vars) | |
safe, rien ne doit avoir été encodé (sinon double encoding), encoding "minimal" pour tout; | |
pas très utile, sauf si on a vraiment besoin (presque jamais) de mettre des charactères nonencodés à un endroit. | |
mode interdit sous peine de sanctions immédiate: | |
.build() (ou synonyme .build(false)) tout seul: ne pas utiliser (mode qui | |
ne fait aucun check, permet le double encoding... code à la php quoi). C'est le | |
mode par défaut lol. | |
Pour renseigner les données: | |
soit donner les données de base (.queryParam, .pathSegment, .host). | |
les autres methodes (fromUriString, path, query) parsent et appellent les setters de base, mais ils font un parsing simpliste qui ne décode pas, | |
donc la nature (encodé ou pas) de leur input doit être prise en compte (pour la contrainte du dessus de soit tout encodé, soit rien encodé) | |
(alors qu'il aurait été possible de faire une API ou ces trucs acceptent des trucs encodés et les décodent pour que ça fonctionne avec le reste non encodé par ex.. ¯\_(ツ)_/¯ ) | |
//Equivalents | |
jshell> UriComponentsBuilder.newInstance().pathSegment("a", "b", "{name}").queryParam("filter", "{filter}").encode().build().expand("nom", "filtre") | |
$21 ==> /a/b/nom?filter=filtre | |
jshell> UriComponentsBuilder.fromUriString("/a/b/{name}?filter={filtre}").encode().build().expand("nom", "filtre") | |
$22 ==> /a/b/nom?filter=filtre | |
//si b doit être un charactère bizarre (ex "|"), pareil | |
jshell> UriComponentsBuilder.newInstance().pathSegment("a", "|", "{name}").queryParam("filter", "{filter}").encode().build().expand("nom", "filtre") | |
$24 ==> /a/%7C/nom?filter=filtre | |
jshell> UriComponentsBuilder.fromUriString("/a/|/{name}?filter={filtre}").encode().build().expand("nom", "filtre") | |
$25 ==> /a/%7C/nom?filter=filtre | |
// par contre, si on a besoin d'escaper un parametre pour faire que le parsing marche, alors on doit se mettre à tout escaper | |
// Ex: maintenant on veut plus mettre a, mais '?' dans le path. | |
// premier essai, pas bon, car le premier ? est interprété par le parsing simple comme le début de la query string | |
// deuxième essai, pas bon, double escaping | |
Base UriComponentsBuilder.fromUriString("/a/|/{name}?filter={filtre}").encode().build().expand("nom", "filtre") | |
?? UriComponentsBuilder.fromUriString("/?/|/{name}?filter={filtre}").encode().build().expand("nom", "filtre") | |
?? UriComponentsBuilder.fromUriString("/%3F/|/{name}?filter={filtre}").encode().build().expand("nom", "filtre") | |
OK UriComponentsBuilder.fromUriString("/%3F/%7C/{name}?filter={filtre}").encode().build().expand("nom", "filtre") | |
mais il a fallu changer 2 trucs pour s'adapter à un changement à cause du parsing ambigü. Donc en utilisant pas le parsing c'est ok direct: | |
jshell> UriComponentsBuilder.newInstance().pathSegment("?", "|", "{name}").queryParam("filter", "{filter}").encode().build().expand("nom", "filtre") | |
$29 ==> /%3F/%7C/nom?filter=filtre | |
2eme aspect: encoding "minimal" vs "maximal" | |
Encoding minimal (pas très utile...): | |
// le & est encodé | |
jshell> UriComponentsBuilder.fromUriString("/").queryParam("a", "&").encode().build() | |
$10 ==> /?a=%26 | |
// pas besoin d'encoder un '?' dans la query string (car elle commence au premier '?' et après plus besoin) | |
jshell> UriComponentsBuilder.fromUriString("/").queryParam("a", "?").encode().build() | |
$9 ==> /?a=? | |
// besoin d'encoder ? dans un pathsegment | |
jshell> UriComponentsBuilder.fromUriString("/").pathSegment("?","foo").encode().build() | |
$34 ==> /%3F/foo | |
encoding "maximal": mode préconisé | |
jshell> UriComponentsBuilder.fromUriString("/").queryParam("a", "{b}").encode().build().expand("?") | |
$30 ==> /?a=%3F | |
//note, tjs possible de faire un encoding "minimal" si on veut avec les templates, mais dans ce cas à quoi servent les templates? | |
//(sauf ptet à découper un peu le code ?) | |
jshell> UriComponentsBuilder.fromUriString("/").queryParam("a", "{b}").build().expand("?").encode() | |
$93 ==> /?a=? | |
toUri() vs toUriString() sont sensé être équivalents.. Uri un peu plus safe car il crée un objet java.net.URI intermediare qui valid (exception si pas bon) | |
mais bon ça veut dire que l'url construite est serialisée par UriComponents puis reparsée par Uri puis reserialisée.. | |
Raccouris à connaitre (pour les utiliser ou les éviter..) | |
* `buildAndExpand(XXX)`: comme `.build().expand(XXX)`: OK | |
* `build(XXX)` comme `.encode().build().expand(XXX).toUri()` : PARFAIT ! mais un peu moins explicite | |
* `toUriString()`: (!! dangereux n'utiliser que si on n'utilise pas de variables.) .build().encode().toUriString() | |
* exemple de danger: | |
jshell> UriComponentsBuilder.fromUriString("/{a}/").uriVariables(Map.of("a","X")).toUriString() | |
$17 ==> "/X/" | |
//OK tout va bien | |
jshell> UriComponentsBuilder.fromUriString("/{a}/").toUriString() | |
$19 ==> "/%7Ba%7D/" | |
//Probablement pas ce qui était voulu si on voulait faire un template ? | |
//Mais si c'était pas un template et vraiment la requete qu'on voulait faire, | |
//alors le résultat a correctement était encodé.. Rare | |
jshell> UriComponentsBuilder.fromUriString("/{b}/").uriVariables(Map.of("a","X")).toUriString() | |
$18 ==> "/{b}/" | |
//uri invalid, '{' et '}' interdits pas escapés !! | |
Bonus1: variables positionnelles ou nommées | |
expand(a,b,c) -> positionnelles | |
expand(Map.of("x", "a", ...) -> nommée | |
Bonus2: variable "pas tout d'un coup": | |
on peut faire `.uriVariables(XXX).encode().build()`: | |
UriComponentsBuilder.fromUriString("/").queryParam("{c}", "{b}").uriVariables(Map.of("c","d")).encode().build().expand("e") | |
Bonus3: uri opaque: (comme URI), plus d'encoding.. | |
UriComponentsBuilder.fromUriString("gridsuitelink:123-aaa-FF").build() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment