Jersey 如何强制URIBuilder.path(…)对参数进行编码,如“0”广告;?这种方法不需要';不要总是正确地用百分比编码参数
如何强制Jersey 如何强制URIBuilder.path(…)对参数进行编码,如“0”广告;?这种方法不需要';不要总是正确地用百分比编码参数,jersey,jax-rs,jersey-1.0,Jersey,Jax Rs,Jersey 1.0,如何强制URIBuilder.path(…)对参数进行编码,如%AD” URIBuilder的path、replacePath和segment方法并不总是正确地对参数进行百分比编码 当参数包含字符“%”后接两个字符,共同构成URL编码字符时,“%”不编码为“%25” 比如说 URI uri = UriBuilder.fromUri("https://dummy.com").queryParam("param", "%AD"); String test = uri.build().toString
URIBuilder.path(…)
对参数进行编码,如%AD”
URIBuilder
的path
、replacePath
和segment
方法并不总是正确地对参数进行百分比编码
当参数包含字符“%”后接两个字符,共同构成URL编码字符时,“%”不编码为“%25”
比如说
URI uri = UriBuilder.fromUri("https://dummy.com").queryParam("param", "%AD");
String test = uri.build().toString();
“测试”是“”但它应该是“”(字符“%”编码为“%25”) 当“%”后面的两个字符是十六进制时,方法
UriBuilderImpl.queryParam(…)
的行为如下。也就是说,方法“com.sun.jersey.api.uri.UriComponent.isHexCharacter(char)”对于“%”后面的字符返回true
我认为UriBuilderImpl的行为是正确的,因为我猜它试图不编码已经编码的参数。但在我的场景中,我永远不会尝试使用已经编码的参数创建URL
我该怎么办?
我的Web应用程序使用Jersey,在许多地方,我使用类UriBuilder构建URI,或者调用UriInfo
对象的方法getBaseUriBuilder
每次调用方法queryParam
、replaceQueryParam
或segment
时,我都可以将“%”替换为“%25”。但我正在寻找一个不那么麻烦的解决方案
如何制作Jersey以返回我自己的UriBuilder实现?
我考虑创建一个扩展UriBuilderImpl的类,该类重写这些方法,并在调用super.queryParam(…)
或其他任何方法之前执行替换
调用UriBuilder.fromURL(…)
、UriInfo.getBaseUriBuilder(…)等时,有没有办法让Jersey返回我自己的UriBuilder而不是UriBuilderImpl
查看方法RuntimeDelegate
,我考虑扩展RuntimeDelegateImpl
。我的实现将覆盖方法createUriBuilder(…)
,该方法将返回我自己的UriBuilder
,而不是UriBuilderImpl
。
然后,我将添加文件META-INF/services/javax.ws.rs.ext.RuntimeDelegate
,并在其中添加我的RuntimeDelegateImpl
的完整类名
问题是jersey-bundle.jar已经包含一个指向com.sun.jersey.server.impl.provider.RuntimeDelegateImpl
的META-INF/services/javax.ws.rs.ext.RuntimeDelegate
,因此容器加载该文件而不是我的javax.ws.rs.ext.RuntimeDelegate
。因此,它不会加载我的RuntimeDelegate
实现
是否可以提供我自己的RuntimeDelegate
实现
我应该采取不同的方法吗?看看下面的例子是否有用。下面链接的线程对可用函数及其不同输出进行了广泛讨论 以下是:
UriBuilder.fromUri(“http://localhost:8080queryParam(“name”,“{value}”).build(“%20”)代码>
UriBuilder.fromUri(“http://localhost:8080queryParam(“name”,“{value}”).buildFromEncoded(“%20”)代码>
UriBuilder.fromUri(“http://localhost:8080replaceQuery(“name={value}).build(“%20”);
UriBuilder.fromUri(“http://localhost:8080replaceQuery(“name={value}).buildFromEncoded(“%20”)代码>
http://localhost:8080?name=%2520
http://localhost:8080?name=%20
http://localhost:8080?name=%2520
http://localhost:8080?name=%20
UriBuilder.fromPath("{arg1}").build("foo#bar");
将导致对“#”进行编码,从而生成的URI
“foo%23bar”。要创建URI“foo#bar”,请使用
相反。URI模板名称和分隔符从不进行编码,而是进行编码
值在构建URI时进行编码。模板参数正则
在构建URI时忽略表达式,即不进行验证
表演
UriBuilder
这可以通过泽西岛的帮助或直接通过Java实现:
UriBuilder.fromUri("https://dummy.com")
.queryParam("param",
UriComponent.encode("%AD",
UriComponent.Type.QUERY_PARAM_SPACE_ENCODED))
.build();
这导致:
https://dummy.com/?param=%25AD
https://dummy.com/?param=%25AD
或:
将导致:
https://dummy.com/?param=%25AD
https://dummy.com/?param=%25AD
对于更复杂的示例(即在查询参数中编码JSON),这种方法也是可能的。假设您有一个类似JSON的{“Entity”:{“foo”:“foo”,“bar”:“bar”}
。使用UriComponent
编码时,查询参数的结果如下所示:
https://dummy.com/?param=%7B%22Entity%22:%7B%22foo%22:%22foo%22,%22bar%22:%22bar%22%7D%7D
[...]
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.ext.RuntimeDelegate;
import com.sun.jersey.api.uri.UriBuilderImpl;
import com.sun.ws.rs.ext.RuntimeDelegateImpl;
// or for jersey2:
// import org.glassfish.jersey.uri.internal.JerseyUriBuilder;
// import org.glassfish.jersey.internal.RuntimeDelegateImpl;
public class SomeBaseClass {
[...]
// this is the lengthier custom implementation of UriBuilder
// replace this with your own according to your needs
public static class AlwaysPercentEncodingUriBuilder extends UriBuilderImpl {
@Override
public UriBuilder queryParam(String name, Object... values) {
Object[] encValues = new Object[values.length];
for (int i=0; i<values.length; i++) {
String value = values[i].toString(); // TODO: better null check here, like in base class
encValues[i] = percentEncode(value);
}
return super.queryParam(name, encValues);
}
private String percentEncode(String value) {
StringBuilder sb = null;
for (int i=0; i < value.length(); i++) {
char c = value.charAt(i);
// if this condition is is true, the base class will not encode the percent
if (c == '%'
&& i + 2 < value.length()
&& isHexCharacter(value.charAt(i + 1))
&& isHexCharacter(value.charAt(i + 2))) {
if (sb == null) {
sb = new StringBuilder(value.substring(0, i));
}
sb.append("%25");
} else {
if (sb != null) sb.append(c);
}
}
return (sb != null) ? sb.toString() : value;
}
// in jersey2 one can call public UriComponent.isHexCharacter
// but in jersey1 we need to provide this on our own
private static boolean isHexCharacter(char c) {
return ('0' <= c && c <= '9')
|| ('A' <=c && c <= 'F')
|| ('a' <=c && c <= 'f');
}
}
// here starts the code to hook up the implementation
public static class AlwaysPercentEncodingRuntimeDelegateImpl extends RuntimeDelegateImpl {
@Override
public UriBuilder createUriBuilder() {
return new AlwaysPercentEncodingUriBuilder();
}
}
static {
RuntimeDelegate myDelegate = new AlwaysPercentEncodingRuntimeDelegateImpl();
RuntimeDelegate.setInstance(myDelegate);
}
}
类似这样的JSON甚至可以通过@QueryParam
注入到资源字段/方法参数中(请参阅)
你用哪种运动衫?在标签中,您提到了Jersey 2,但在
RuntimeDelegate
部分,您使用的是Jersey 1的东西。可以在启动时手动覆盖Jersey中的默认行为,例如使用调用RuntimeDelegate.setInstance(yourRuntimeDelegateImpl)
的静态帮助程序
因此,如果您希望有一个UriBuilder对百分比进行编码,即使它们看起来像是已编码序列的一部分,这将类似于:
https://dummy.com/?param=%7B%22Entity%22:%7B%22foo%22:%22foo%22,%22bar%22:%22bar%22%7D%7D
[...]
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.ext.RuntimeDelegate;
import com.sun.jersey.api.uri.UriBuilderImpl;
import com.sun.ws.rs.ext.RuntimeDelegateImpl;
// or for jersey2:
// import org.glassfish.jersey.uri.internal.JerseyUriBuilder;
// import org.glassfish.jersey.internal.RuntimeDelegateImpl;
public class SomeBaseClass {
[...]
// this is the lengthier custom implementation of UriBuilder
// replace this with your own according to your needs
public static class AlwaysPercentEncodingUriBuilder extends UriBuilderImpl {
@Override
public UriBuilder queryParam(String name, Object... values) {
Object[] encValues = new Object[values.length];
for (int i=0; i<values.length; i++) {
String value = values[i].toString(); // TODO: better null check here, like in base class
encValues[i] = percentEncode(value);
}
return super.queryParam(name, encValues);
}
private String percentEncode(String value) {
StringBuilder sb = null;
for (int i=0; i < value.length(); i++) {
char c = value.charAt(i);
// if this condition is is true, the base class will not encode the percent
if (c == '%'
&& i + 2 < value.length()
&& isHexCharacter(value.charAt(i + 1))
&& isHexCharacter(value.charAt(i + 2))) {
if (sb == null) {
sb = new StringBuilder(value.substring(0, i));
}
sb.append("%25");
} else {
if (sb != null) sb.append(c);
}
}
return (sb != null) ? sb.toString() : value;
}
// in jersey2 one can call public UriComponent.isHexCharacter
// but in jersey1 we need to provide this on our own
private static boolean isHexCharacter(char c) {
return ('0' <= c && c <= '9')
|| ('A' <=c && c <= 'F')
|| ('a' <=c && c <= 'f');
}
}
// here starts the code to hook up the implementation
public static class AlwaysPercentEncodingRuntimeDelegateImpl extends RuntimeDelegateImpl {
@Override
public UriBuilder createUriBuilder() {
return new AlwaysPercentEncodingUriBuilder();
}
}
static {
RuntimeDelegate myDelegate = new AlwaysPercentEncodingRuntimeDelegateImpl();
RuntimeDelegate.setInstance(myDelegate);
}
}
[…]
导入javax.ws.rs.core.UriBuilder;
导入javax.ws.rs.ext.RuntimeDelegate;
导入com.sun.jersey.api.uri.UriBuilderImpl;
导入com.sun.ws.rs.ext.RuntimeDelegateImpl;
//或运动衫2:
//导入org.glassfish.jersey.uri.internal.JerseyUriBuilder;
//导入org.glassfish.jersey.internal.RuntimeDelegateImpl;
公共类SomeBaseClass{
[...]
//这是UriBuilder更长的自定义实现
//更换