写代码的能力上看,文心一言3.5的能力已经很强了,能够和GPT-4各有千秋。
我这里只贴出了GPT-4的实现,文心一言3.5的代码实现也是类似的,只是会提示JDK没有实现SHA-3-256,需要引入第三方库。但是生成的单元测试用例明显好于GPT-4,对于边界条件验证的更加充分。足够用了,关键文心一言3.5还免费。
业务功能:
对于任意HTTP请求,都可以基于URI和请求参数/参数值对请求进行散列,计算出http请求的散列字符串值sign来。
服务端强制要求每一个HTTP请求都必须包含sign参数和值。
确保不知道prefix具体值的任何用户都无法构造出一个有效HTTP请求。
提示词:
请写一个Java类,利用SHA-3算法来对http的GET/POST请求URI和参数以及参数值进行散列和校验。
1)静态的常量字符串 prefix,由随机字符构成的字符串,长度为32个字符。
方法1)求HTTP请求URI和参数、参数值的生成SHA-3散列字符串值
输入参数:
参数1,名称为 httpURI,类型为String,是HTTP请求的URI的字符串;
参数2,名称为 parameters,类型是HashMap<String,String>,其中key为HTTP请求的参数,value为参数对应的字符串值;
返回值:
返回值为String,为httpURI和参数parameters使用SHA-3算法来散列后的字符串值,用sign来表示。
方法要求:
待散列的字符串 : httpURI?key1=value1&key2=value2&key3=value3&prefix
其中key1/key2/key3是严格按照参数名称的ASCII码升序排列后的参数名称;
其中value1/value2/value3是对应的参数key1/key2/key3的值,参数值需要采用URL编码;
其中prefix表示一个加盐字符串,prefix的内容不会出现在用户的HTTP请求中,而是服务端写死的字符串值;
方法2)根据HTTP请求的URI和参数、参数值以及本次请求的散列码来判定请求是否合法
输入参数:
参数1,名称为 httpURI,类型为String,是HTTP请求的URI的字符串;
参数2,名称为 parameters,类型是HashMap<String,String>,其中key为HTTP请求的参数,value为参数对应的字符串值;
返回值:
返回值为boolean,表示对于HTTP请求的URI和参数名称/参数值的SHA-3校验是否通过,通过则返回true。
方法要求:
参数2中必须要包含 一个参数 sign,该参数值不能为空,为空则校验不通过。
把方法2的参数用方法1来计算一个SHA-3的散列值,注意参数sign和sign的值不能参加散列。
用计算出来的散列字符串和HTTP请求中的sign参数的值进行比较,两个字符串值完全一致则认为校验结果为true,反之为false。
GPT-4生成的代码如下:
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.net.URLEncoder;
public class HttpSignatureValidator {
// 静态常量字符串prefix,由随机字符构成的字符串,长度为32个字符
private static final String PREFIX = "abcdefghijklmnopqrstuvwxyz123456"; // 示例
// 方法1: 生成SHA-3散列字符串值
public static String generateSignature(String httpURI, HashMap<String, String> parameters) throws NoSuchAlgorithmException {
// 按ASCII码升序排列参数,并进行URL编码
String sortedParameters = parameters.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(entry -> entry.getKey() + "=" + urlEncode(entry.getValue()))
.collect(Collectors.joining("&"));
// 待散列的字符串
String toHash = httpURI + "?" + sortedParameters + "&" + PREFIX;
return hashSHA3(toHash);
}
// 方法2: 根据HTTP请求的URI和参数、参数值以及本次请求的散列码判断请求是否合法
public static boolean validateRequest(String httpURI, HashMap<String, String> parameters) throws NoSuchAlgorithmException {
String providedSignature = parameters.get("sign");
// 如果sign为空或不存在,则校验不通过
if (providedSignature == null || providedSignature.isEmpty()) {
return false;
}
// 从参数中移除sign后进行散列
parameters.remove("sign");
String calculatedSignature = generateSignature(httpURI, parameters);
return providedSignature.equals(calculatedSignature);
}
// 对字符串进行URL编码
private static String urlEncode(String value) {
try {
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
} catch (Exception e) {
return ""; // 简化处理
}
}
// 使用SHA-3算法进行散列
private static String hashSHA3(String data) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA3-256");
byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
}
// 字节数组转为十六进制字符串
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte aByte : bytes) {
String hex = Integer.toHexString(0xff & aByte);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
// 测试方法
public static void main(String[] args) throws Exception {
HashMap<String, String> parameters = new HashMap<>();
parameters.put("key1", "value1");
parameters.put("key2", "value2");
parameters.put("key3", "value3");
String httpURI = "/api/test";
String signature = generateSignature(httpURI, parameters);
System.out.println("Signature: " + signature);
parameters.put("sign", signature);
boolean isValid = validateRequest(httpURI, parameters);
System.out.println("Request is valid: " + isValid);
}
}
复制代码在JAVA环境下直接可用。
接下来让GPT-4来生成单元测试代码。
提示词:
给上述JAVA类和方法生成单元测试用例,注意边界用例不能遗漏,保证测试通过后的代码能够在健壮、正确,直接生产环境可用。
GPT-4生成的单元测试代码:
import static org.junit.Assert.*;
import org.junit.Test;
import java.util.HashMap;
public class HttpSignatureValidatorTest {
// 测试正常情况下的散列和验证
@Test
public void testValidSignatureAndValidation() throws Exception {
String httpURI = "/api/test";
HashMap<String, String> parameters = new HashMap<>();
parameters.put("key1", "value1");
parameters.put("key2", "value2");
parameters.put("key3", "value3");
String signature = HttpSignatureValidator.generateSignature(httpURI, parameters);
assertNotNull(signature);
parameters.put("sign", signature);
assertTrue(HttpSignatureValidator.validateRequest(httpURI, parameters));
}
// 测试参数为空的情况
@Test
public void testEmptyParameters() throws Exception {
String httpURI = "/api/test";
HashMap<String, String> parameters = new HashMap<>();
String signature = HttpSignatureValidator.generateSignature(httpURI, parameters);
assertNotNull(signature);
parameters.put("sign", signature);
assertTrue(HttpSignatureValidator.validateRequest(httpURI, parameters));
}
// 测试参数值包含特殊字符
@Test
public void testParametersWithSpecialChars() throws Exception {
String httpURI = "/api/test";
HashMap<String, String> parameters = new HashMap<>();
parameters.put("key1", "value 1&value=2");
String signature = HttpSignatureValidator.generateSignature(httpURI, parameters);
assertNotNull(signature);
parameters.put("sign", signature);
assertTrue(HttpSignatureValidator.validateRequest(httpURI, parameters));
}
// 测试sign参数不存在的情况
@Test
public void testNoSignParameter() throws Exception {
String httpURI = "/api/test";
HashMap<String, String> parameters = new HashMap<>();
parameters.put("key1", "value1");
assertFalse(HttpSignatureValidator.validateRequest(httpURI, parameters));
}
// 测试使用错误的sign值进行验证
@Test
public void testInvalidSign() throws Exception {
String httpURI = "/api/test";
HashMap<String, String> parameters = new HashMap<>();
parameters.put("key1", "value1");
parameters.put("sign", "invalid");
assertFalse(HttpSignatureValidator.validateRequest(httpURI, parameters));
}
}
单元测试代码是直接可用的。