如何在无Maven依赖、不使用SDK的情况下用纯Java上传文件至Amazon S3
纯Java无依赖上传文本文件到Amazon S3
当然可以,直接调用Amazon S3的REST API就能实现,不需要任何外部依赖。核心是手动实现AWS的签名认证逻辑,然后构造HTTP PUT请求上传文本内容。
步骤说明
- 提前准备好AWS访问密钥(Access Key ID + Secret Access Key)、S3存储桶名称、存储桶所在区域,以及要上传的文本内容和目标对象键(即文件在S3里的路径/名称)。
- 核心是生成符合AWS v4签名规范的认证头,这一步用Java自带的
javax.crypto和java.net包就能实现。
完整代码示例
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; public class S3TextUploader { private static final String AWS_ACCESS_KEY = "你的AWS Access Key ID"; private static final String AWS_SECRET_KEY = "你的AWS Secret Access Key"; private static final String BUCKET_NAME = "你的存储桶名称"; private static final String REGION = "存储桶区域(比如us-east-1)"; private static final String OBJECT_KEY = "目标对象键(比如test.txt)"; private static final String TEXT_CONTENT = "要上传的文本内容"; public static void main(String[] args) throws Exception { // 生成日期和时间戳(符合AWS要求的格式) SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); String currentDate = dateFormat.format(new Date()); String dateStamp = currentDate.substring(0, 8); // 1. 构造待签名字符串 String httpMethod = "PUT"; String canonicalUri = "/" + OBJECT_KEY; String canonicalQueryString = ""; String canonicalHeaders = "host:" + BUCKET_NAME + ".s3." + REGION + ".amazonaws.com\n" + "x-amz-content-sha256:" + sha256Hash(TEXT_CONTENT.getBytes(StandardCharsets.UTF_8)) + "\n" + "x-amz-date:" + currentDate + "\n"; String signedHeaders = "host;x-amz-content-sha256;x-amz-date"; String payloadHash = sha256Hash(TEXT_CONTENT.getBytes(StandardCharsets.UTF_8)); String canonicalRequest = httpMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + payloadHash; // 2. 构造签名字符串 String algorithm = "AWS4-HMAC-SHA256"; String credentialScope = dateStamp + "/" + REGION + "/s3/aws4_request"; String stringToSign = algorithm + "\n" + currentDate + "\n" + credentialScope + "\n" + sha256Hash(canonicalRequest.getBytes(StandardCharsets.UTF_8)); // 3. 计算签名 byte[] signingKey = getSigningKey(AWS_SECRET_KEY, dateStamp, REGION, "s3"); String signature = bytesToHex(hmacSha256(signingKey, stringToSign.getBytes(StandardCharsets.UTF_8))); // 4. 构造Authorization头 String authorizationHeader = algorithm + " " + "Credential=" + AWS_ACCESS_KEY + "/" + credentialScope + ", " + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature; // 5. 发送PUT请求 URL url = new URL("https://" + BUCKET_NAME + ".s3." + REGION + ".amazonaws.com/" + OBJECT_KEY); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("PUT"); connection.setDoOutput(true); // 设置请求头 connection.setRequestProperty("Host", BUCKET_NAME + ".s3." + REGION + ".amazonaws.com"); connection.setRequestProperty("x-amz-date", currentDate); connection.setRequestProperty("x-amz-content-sha256", payloadHash); connection.setRequestProperty("Authorization", authorizationHeader); connection.setRequestProperty("Content-Type", "text/plain; charset=UTF-8"); // 写入文本内容 try (OutputStream os = connection.getOutputStream()) { os.write(TEXT_CONTENT.getBytes(StandardCharsets.UTF_8)); } // 检查响应状态 int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED) { System.out.println("文本上传成功!"); } else { System.out.println("上传失败,响应码:" + responseCode); System.out.println("响应信息:" + connection.getResponseMessage()); } } // 计算SHA256哈希并转为十六进制字符串 private static String sha256Hash(byte[] input) throws Exception { java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(input); return bytesToHex(digest); } // 计算HMAC-SHA256 private static byte[] hmacSha256(byte[] key, byte[] data) throws Exception { Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(key, "HmacSHA256")); return mac.doFinal(data); } // 生成AWS v4签名密钥 private static byte[] getSigningKey(String secretKey, String dateStamp, String regionName, String serviceName) throws Exception { byte[] kSecret = ("AWS4" + secretKey).getBytes(StandardCharsets.UTF_8); byte[] kDate = hmacSha256(kSecret, dateStamp.getBytes(StandardCharsets.UTF_8)); byte[] kRegion = hmacSha256(kDate, regionName.getBytes(StandardCharsets.UTF_8)); byte[] kService = hmacSha256(kRegion, serviceName.getBytes(StandardCharsets.UTF_8)); return hmacSha256(kService, "aws4_request".getBytes(StandardCharsets.UTF_8)); } // 字节数组转十六进制字符串 private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } }
注意事项
- 替换代码中的占位符(AWS密钥、存储桶信息、文本内容等)为你自己的实际数据。
- 确保你的AWS密钥拥有S3的
PutObject权限,避免权限不足导致上传失败。 - 如果上传的文本内容较大,考虑分块上传,但对于常规文本文件,上述代码足够使用。
- 日期和时间必须使用UTC时区,否则签名会验证失败。
内容的提问来源于stack exchange,提问作者KisnardOnline
相关产品推荐
相关产品推荐

