使用生成的客户端代码无法上传文件
File upload not working using generated client code
我有一个简单的 input
用于从本地驱动器中选择文件:
<input type="file" (change)="onUpload($event)" required/>
选择文件后,我想将其上传到我的服务器。
为此,我实际上使用了一个公开接口的生成客户端:
// Generated Client Code
// .. file.d.ts
export interface File {
file?: Blob;
}
// .. rest-client.d.ts
postTrack(file, observe = 'body', reportProgress = false) {
if (file === null || file === undefined) {
throw new Error('Required parameter file was null or undefined when calling postTrack.');
}
let queryParameters = new HttpParams({ encoder: this.encoder });
if (file !== undefined && file !== null) {
queryParameters = queryParameters.set('file', file);
}
let headers = this.defaultHeaders;
// to determine the Accept header
const httpHeaderAccepts = [
'multipart/form-data'
];
const httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
return this.httpClient.post(`${this.configuration.basePath}/api/tracks`, null, {
params: queryParameters,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
});
}
上传的内容如下所示:
onUpload(event) {
this.uploadAndProgress(event.target.files);
}
uploadAndProgress(files: File[]) {
// Method 1 - Pass file object directly
const file = files[0];
// Method 2 - Append file object to FormData
const file = new FormData();
file.append('file', files[0]);
this.apiGateway.postTrack(file, 'events',true)
.subscribe((event) => {
if (event.type === HttpEventType.UploadProgress) {
this.percentDone = Math.round(100 * event.loaded / event.total);
} else if (event instanceof HttpResponse) {
this.uploadSuccess = true;
}
});
}
但是,它不起作用,因为 POST 请求 URL 看起来像这样:https://localhost:8443/api/tracks?file=%5Bobject%20Object%5D(对于方法 1 和方法 2),我收到此响应:
{
"timestamp": "2020-01-25T22:16:27.727+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Current request is not a multipart request",
"trace": "org.springframework.web.multipart.MultipartException: Current request is not a multipart request\n...",
"path": "/api/tracks"
}
在服务器端,我有这个端点,它目前负责在别处存储该文件:
@RequestMapping(value = "/tracks", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public @ResponseBody
String postTrack(
@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes
) {
storageService.store(file);
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
return "redirect:/";
}
我不太确定我必须做什么才能完成这项工作。
我很确定问题是我应该将文件作为 Blob
发送。但是,我找不到将 File
对象转换为 Blob
.
的方法
原来问题出在生成的代码上(参见 github issue)。
总结一下:
@RequestParam
尚不支持,但将从
的下一个版本开始
springdoc-openapi 1.2.29
另请注意 consumes
不受支持:
@RequestMapping(value = "/tracks", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
相反,我不得不像这样添加 @ApiResponse
:
@RequestMapping(value = "/tracks", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiResponse(description = "Successful Operation", responseCode = "200", content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE))
生成的 TypeScript 客户端代码现在如下所示:
postTrack(file, observe = 'body', reportProgress = false) {
let headers = this.defaultHeaders;
// to determine the Accept header
const httpHeaderAccepts = [
'multipart/form-data'
];
const httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes = [
'multipart/form-data'
];
const canConsumeForm = this.canConsumeForm(consumes);
let formParams;
let useForm = false;
let convertFormParamsToString = false;
// use FormData to transmit files using content-type "multipart/form-data"
// see
useForm = canConsumeForm;
if (useForm) {
formParams = new FormData();
}
else {
formParams = new HttpParams({ encoder: this.encoder });
}
if (file !== undefined) {
formParams = formParams.append('file', file) || formParams;
}
return this.httpClient.post(`${this.configuration.basePath}/api/tracks`, convertFormParamsToString ? formParams.toString() : formParams, {
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
});
}
我有一个简单的 input
用于从本地驱动器中选择文件:
<input type="file" (change)="onUpload($event)" required/>
选择文件后,我想将其上传到我的服务器。
为此,我实际上使用了一个公开接口的生成客户端:
// Generated Client Code
// .. file.d.ts
export interface File {
file?: Blob;
}
// .. rest-client.d.ts
postTrack(file, observe = 'body', reportProgress = false) {
if (file === null || file === undefined) {
throw new Error('Required parameter file was null or undefined when calling postTrack.');
}
let queryParameters = new HttpParams({ encoder: this.encoder });
if (file !== undefined && file !== null) {
queryParameters = queryParameters.set('file', file);
}
let headers = this.defaultHeaders;
// to determine the Accept header
const httpHeaderAccepts = [
'multipart/form-data'
];
const httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
return this.httpClient.post(`${this.configuration.basePath}/api/tracks`, null, {
params: queryParameters,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
});
}
上传的内容如下所示:
onUpload(event) {
this.uploadAndProgress(event.target.files);
}
uploadAndProgress(files: File[]) {
// Method 1 - Pass file object directly
const file = files[0];
// Method 2 - Append file object to FormData
const file = new FormData();
file.append('file', files[0]);
this.apiGateway.postTrack(file, 'events',true)
.subscribe((event) => {
if (event.type === HttpEventType.UploadProgress) {
this.percentDone = Math.round(100 * event.loaded / event.total);
} else if (event instanceof HttpResponse) {
this.uploadSuccess = true;
}
});
}
但是,它不起作用,因为 POST 请求 URL 看起来像这样:https://localhost:8443/api/tracks?file=%5Bobject%20Object%5D(对于方法 1 和方法 2),我收到此响应:
{
"timestamp": "2020-01-25T22:16:27.727+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Current request is not a multipart request",
"trace": "org.springframework.web.multipart.MultipartException: Current request is not a multipart request\n...",
"path": "/api/tracks"
}
在服务器端,我有这个端点,它目前负责在别处存储该文件:
@RequestMapping(value = "/tracks", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public @ResponseBody
String postTrack(
@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes
) {
storageService.store(file);
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
return "redirect:/";
}
我不太确定我必须做什么才能完成这项工作。
我很确定问题是我应该将文件作为 Blob
发送。但是,我找不到将 File
对象转换为 Blob
.
原来问题出在生成的代码上(参见 github issue)。
总结一下:
@RequestParam
尚不支持,但将从
springdoc-openapi 1.2.29
另请注意 consumes
不受支持:
@RequestMapping(value = "/tracks", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
相反,我不得不像这样添加 @ApiResponse
:
@RequestMapping(value = "/tracks", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiResponse(description = "Successful Operation", responseCode = "200", content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE))
生成的 TypeScript 客户端代码现在如下所示:
postTrack(file, observe = 'body', reportProgress = false) {
let headers = this.defaultHeaders;
// to determine the Accept header
const httpHeaderAccepts = [
'multipart/form-data'
];
const httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes = [
'multipart/form-data'
];
const canConsumeForm = this.canConsumeForm(consumes);
let formParams;
let useForm = false;
let convertFormParamsToString = false;
// use FormData to transmit files using content-type "multipart/form-data"
// see
useForm = canConsumeForm;
if (useForm) {
formParams = new FormData();
}
else {
formParams = new HttpParams({ encoder: this.encoder });
}
if (file !== undefined) {
formParams = formParams.append('file', file) || formParams;
}
return this.httpClient.post(`${this.configuration.basePath}/api/tracks`, convertFormParamsToString ? formParams.toString() : formParams, {
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
});
}