我有一个MVC应用程序,该应用程序托管在Windows Server 2016 AWS EC2实例上。此应用程序是一个管理工具。该应用程序使用Web API应用程序,该应用程序作为AWS Lambda Serverless应用程序(https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/lambda-build-test-severless-app.html)托管。
我的MVC应用程序的一个区域允许用户使用表单文件输入上传图像。然后将其发布回MVC控制器,并发送到API实用程序,该实用程序会将文件发送到API。然后,API会调整大小(使用Magick.NET),并将图像保存到S3存储桶中,并将结果URL保存到MySQL数据库中。
在我的计算机上本地运行时,所有这些都可以完美运行。问题是当我尝试在实时网站上上传图像时。结果是,当图像数据加载到MagickImage中时,出现以下错误:
ImageMagick.MagickCorruptImageErrorException:不是JPEG文件:开始 带有0xef 0xbf`'@ error / jpeg.c / JPEGErrorHandler / 332 \ n
我添加了一些代码来记录数据的前20个字节(字节数组),无论是在MVC应用程序中(在将文件发布到API之前)还是在收到文件后在API中。我发现我收到的值完全不同,如下所示:
- MVC :FF-D8-FF-E0-00-10-4A-46-49-46-00-01-01-01-01-2C-01-2C-00- 00
- API::EF-BF-BD-EF-BF-BD-EF-BF-BD-EF-BF-BD-00-10-4A-46-49-46-00- 01
然后我在本地运行时执行以下操作,并看到输出的值相同:
- MVC :FF-D8-FF-E0-00-10-4A-46-49-46-00-01-01-01-01-2C-01-2C-00- 00
- API::FF-D8-FF-E0-00-10-4A-46-49-46-00-01-01-01-01-2C-01-2C-00- 00
我是否需要设置/更改某种环境设置,这可能会导致这种奇怪的行为?
下面是按发生顺序排列的相关代码的不同部分。
MVC控制器:
public async Task<IActionResult> AddImage(ImageFormViewModel viewModel)
{
if (!ModelState.IsValid)
{
return RedirectToAction("Details", new { id = viewModel.TourId, errors = string.Join(",", ViewData.ModelState.Values.SelectMany(x => x.Errors.Select(y => y.ErrorMessage))) });
}
var apiResponse = await this.api.PostFile<ApiResponse>($"tours/{viewModel.TourId}/images", viewModel.Image);
if (apiResponse.Success)
{
return RedirectToAction("Details", new { id = viewModel.TourId, message = "Image added successfully!" });
}
{
return RedirectToAction("Details", new { id = viewModel.TourId, errors = string.Join(",", apiResponse.Errors) });
}
}
API实用程序(在MVC应用中):
public async Task<TResponse> PostFile<TResponse>(string uri, IFormFile file) where TResponse : ApiResponse
{
var response = default(TResponse);
if (file != null && file.Length > 0)
{
var url = (!string.IsNullOrWhiteSpace(uri) ? new Uri(new Uri(this.baseUrl), uri) : new Uri(this.baseUrl)).ToString();
using (var http = new HttpClient())
{
byte[] data;
using (var stream = new MemoryStream())
{
await file.CopyToAsync(stream);
data = stream.ToArray();
}
this.logger.Information("First bytes (MVC app): " + BitConverter.ToString(data.Take(20).ToArray()));
var content = new MultipartFormDataContent();
content.Add(new ByteArrayContent(data), "file", file.FileName);
var httpResponse = await http.PostAsync(url, content);
response = JsonConvert.DeserializeObject<TResponse>(await httpResponse.Content.ReadAsStringAsync());
}
}
return response;
}
API控制器:
[HttpPost]
public async Task<IActionResult> Post([FromRoute]string tourId)
{
var response = new ApiResponse();
if (Request.HasFormContentType)
{
var form = Request.Form;
foreach (var formFile in form.Files)
{
using (var stream = new MemoryStream())
{
await formFile.CopyToAsync(stream);
var result = await this.tourManagementService.AddImage(HttpUtility.UrlDecode(tourId), Path.GetFileNameWithoutExtension(formFile.FileName), stream.ToArray());
if (!result.Success)
{
...
}
}
}
}
return Ok(response);
}
保存图像等的服务方法:
public async Task<AddImageResult> AddImage(string tourId, string imageName, byte[] imageData)
{
this.logger.Information("First bytes (API): " + BitConverter.ToString(imageData.Take(20).ToArray()));
...
}
使用Magick.NET并引发异常的代码:
private byte[] resizeImage(byte[] imageData, int width, int height)
{
using (var image = new MagickImage(imageData, new MagickReadSettings { Format = MagickFormat.Jpeg }))
{
...
}
}
答案 0 :(得分:0)
原来的问题是我的AWS API Gateway不接受二进制数据。默认情况下,API网关将消息正文视为JSON,如此处所述-https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings.html
默认情况下,API Gateway将消息正文视为文本有效内容,并且 应用任何预配置的映射模板来转换JSON 字符串。
我相信腐败是腐败的根源。为了解决这个问题,我必须在如下所示的API Gateway中添加“ image / jpeg”作为可接受的二进制媒体类型:
然后我调整了代码以处理二进制数据(并废弃了表单内容):
MVC端:
public async Task<TResponse> PostFile<TResponse>(string uri, IFormFile file) where TResponse : ApiResponse
{
var response = default(TResponse);
if (file != null && file.Length > 0)
{
var url = (!string.IsNullOrWhiteSpace(uri) ? new Uri(new Uri(this.baseUrl), uri) : new Uri(this.baseUrl)).ToString();
using (var http = new HttpClient())
{
var content = new StreamContent(file.OpenReadStream());
content.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType);
var httpResponse = await http.PostAsync(url, content);
response = JsonConvert.DeserializeObject<TResponse>(await httpResponse.Content.ReadAsStringAsync());
}
}
return response;
}
API端:
[HttpPost]
public async Task<IActionResult> Post([FromRoute]string tourId)
{
var response = new ApiResponse();
if (Request.ContentType.Equals("image/jpeg"))
{
using (var stream = new MemoryStream())
{
await Request.Body.CopyToAsync(stream);
...
}
}
else
{
...
}
return Ok(response);
}