英文:
Spring RestTemplate: getting 403 forbidden for multipart/form-data but working with curl
问题
以下是翻译后的内容:
我正在使用 Spring 的 RestTemplate 来进行一个 POST 请求,请求中包含一个文件和一个字符串参数。以下是代码示例:
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer ...");
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
File file = new File("src/main/resources/test.json");
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
byte[] fileBytes = toByteArray(in);
MultiValueMap<String, String> fileMap = new LinkedMultiValueMap<>();
ContentDisposition contentDisposition = ContentDisposition
.builder("form-data")
.name("file")
.filename("test.json")
.build();
fileMap.add(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString());
fileMap.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
org.springframework.http.HttpEntity<byte[]> fileEntity =
new org.springframework.http.HttpEntity<>(fileBytes, fileMap);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("stringFormInput", "xyz");
body.add("file", fileEntity);
org.springframework.http.HttpEntity<MultiValueMap<String, Object>> entity =
new org.springframework.http.HttpEntity<>(body, httpHeaders);
ResponseEntity<JsonNode> responseEntity =
restTemplate.postForEntity("https://uploadFile", entity, JsonNode.class);
但我得到了一个 403 FORBIDDEN
的响应。
然而,如果我使用下面的 curl 命令,请求可以成功执行:
curl --location --request POST 'https://uploadFile' \
--header 'Content-Type: multipart/form-data' \
--header 'Authorization: Bearer ...' \
--form 'file=@/D:/resources/test.json' \
--form 'stringFormInput=xyz'
我还尝试使用 httpClient
,但依然得到 403 错误,没有任何错误信息。
HttpPost post = new HttpPost("https://uploadFile");
post.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE);
post.setHeader(HttpHeaders.AUTHORIZATION, "Bearer ...");
File file = new File("src/main/resources/test.json");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("file", file, ContentType.DEFAULT_BINARY, "test.json");
builder.addTextBody("stringFormInput", "xyz", ContentType.DEFAULT_BINARY);
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse response = httpClient.execute(post);
编辑
目前,我通过在 Java 中执行 curl 命令来绕过了这个问题:
File file = new File("src/main/resources/test.json");
String[] command = {"curl", "--location",
"--request", "POST", "https://uploadFile",
"--header", "Content-Type: multipart/form-data",
"--header", "Authorization: Bearer ...",
"-F", "file=@" + file.getPath(),
"--form", "stringFormInput=xyz"};
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
String curlResult = "";
String line = "";
try {
Process process = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(process.getInputStream()));
while (true) {
line = r.readLine();
if (line == null) {
break;
}
curlResult = curlResult + line;
}
} catch (Exception e) {
e.printStackTrace();
}
英文:
I am using spring rest-template to POST request form-data
of 1 file and 1 string parameter, here is code:
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer ...");
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
File file=new File("src\main\resources\test.json");
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
byte[] fileBytes = toByteArray(in);
MultiValueMap<String, String> fileMap = new LinkedMultiValueMap<>();
ContentDisposition contentDisposition = ContentDisposition
.builder("form-data")
.name("file")
.filename("test.json")
.build();
fileMap.add(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString());
fileMap.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
org.springframework.http.HttpEntity<byte[]> fileEntity =
new org.springframework.http.HttpEntity<>(fileBytes, fileMap);
MultiValueMap< String, Object > body = new LinkedMultiValueMap<>();
body.add("stringFormInput", "xyz");
body.add("file", fileEntity);
org.springframework.http.HttpEntity< MultiValueMap< String, Object > > entity =
new org.springframework.http.HttpEntity<>(body, httpHeaders);
ResponseEntity< JsonNode > responseEntity =
restTemplate.postForEntity("https://uploadFile", entity, JsonNode.class);
But I'm getting 403 FORBIDDEN
response
However, If I use curl command below, it executes successfully
curl --location --request POST 'https://uploadFile' \
--header 'Content-Type: multipart/form-data' \
--header 'Authorization: Bearer ...' \
--form 'file=@/D:/resources/test.json' \
--form 'stringFormInput=xyz' \
I also tried with httpClient
, still, it is 403 with no any cause message
HttpPost post = new HttpPost("https://uploadFile");
post.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE);
post.setHeader(HttpHeaders.AUTHORIZATION, "Bearer ...");
File file=new File("src\main\resources\test.json");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("file", file, ContentType.DEFAULT_BINARY, "test.json");
builder.addTextBody("stringFormInput", "xyz", ContentType.DEFAULT_BINARY);
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse response = httpClient.execute(post);
EDIT
For now I did a workaround by executing curl from JAVA
File file=new File("src\main\resources\test.json");
String[] command = {"curl", "--location",
"--request", "POST", "https://uploadFile",
"--header", "Content-Type: multipart/form-data",
"--header", "Authorization: Bearer ...",
"-F", "file=" + "@"+file.getPath(),
"--form", "stringFormInput=xyz"};
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
String curlResult = "";
String line = "";
try {
Process process = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(process.getInputStream()));
while (true) {
line = r.readLine();
if (line == null) {
break;
}
curlResult = curlResult + line;
}
} catch (Exception e) {
e.printStackTrace();
}
答案1
得分: 1
我遇到了类似的问题,cURL 能够正常执行,但 Spring 代码却返回 403 错误。
问题出在接收该请求的目标位置。一些 Web 服务器,如 Nginx,默认情况下需要强制性的头部信息,比如 "User-Agent",这个可以被禁用。
Spring 默认情况下不会传递额外的头部信息。如果目标使用了 Nginx,尝试添加 "User-Agent" 头部,或者查找他们使用了哪种 Web 服务器。
以下是我用于参考的代码。
-
这段代码返回 403 错误。
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); -
这段代码运行正常。
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
httpHeaders.add("User-Agent", "PostmanRuntime/7.26.3");
英文:
So I faced a similar problem that cURL was executing properly but Spring code was giving 403.
The problem lies with the target which is receiving this request. Few web servers like Nginx required mandatory headers like "User-Agent" by default which can be disabled.
By default, Spring doesn't pass any extra header. Try adding "User-Agent" if the target is using Ngnix or find what web server they are using.
Sharing my code for reference.
-
This code gave 403
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); -
this code worked fine.
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
httpHeaders.add("User-Agent", "PostmanRuntime/7.26.3");
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论