给定一个输入参数,对于rest api,我想将哈希码用作etag。 json响应发生变化的概率是多少,而哈希码也是一样的?
或者有更好的方法吗?
@GET
public Response getConfigurationForView(@PathParam("in1") String in1, @Context Request request) throws Exception {
String jsonResponse = getJsonResponse(in1);
EntityTag etag = new EntityTag(Integer.toString(in1.hashCode()) + "-" + Integer.toString(jsonResponse.hashCode()));
ResponseBuilder builder = request.evaluatePreconditions(etag);
if(builder == null){
builder = Response.ok(jsonResponse, MediaType.APPLICATION_JSON);
builder.tag(etag);
}
return builder.build();
}
答案 0 :(得分:3)
鉴于你只有40亿个可能的哈希码用于各种各样的字符串,你有可能最终遇到ETag冲突。
了解String.hashCode()
的实施方式:
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
- 你甚至可以自己想出可能的碰撞。例如,""
(空字符串)和"\0"
(仅包含\0
字符的字符串)将为您提供相同的hashCode
0。
我建议您使用SHA1哈希(或MD5,但请先在security和CPU running time上查看这些说明。)
如果您继续使用SHA1哈希,您的代码可能如下所示:
public static String calculateEtag(final String s) throws java.security.NoSuchAlgorithmException {
final java.nio.ByteBuffer buf = java.nio.charset.StandardCharsets.UTF_8.encode(s);
final java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA1");
buf.mark();
digest.update(buf);
buf.reset();
return String.format("W/\"%s\"", javax.xml.bind.DatatypeConverter.printHexBinary(digest.digest()));
}
这将产生与sha1sum
实用程序相同的输出。
您也可以使用BigInteger
将字节缓冲区转换为十六进制字符串:
new BigInteger(1, digest.digest()).toString(16)
- 但javax.xml.bind.DatatypeConverter.printHexBinary()
要快几倍。
答案 1 :(得分:0)
如果你可以使用jdk8 +和Google Guava,你可以试试
final String myETag = ( (Set<Object>) this.setOfChangeableProperties ).stream()
.filter( Objects::nonNull )
.map( Objects::toString )
.reduce( (a,b) -> a.concat(b) )
.map( s -> Hashing.md5().hashUnencodedChars( s ).toString() )
.orElse( "nothing of interest to hash!" )