【发布时间】:2020-04-08 12:02:22
【问题描述】:
有人提出了类似的问题,但在浏览了所有这些以及有关该主题的许多博客文章后,我无法弄清楚这一点,所以请原谅我。
我正在创建一个简单的博客,其中包含(出于此问题的目的)两部分,Angular 8 中的前端 SPA 和 ASP.NET Core 3 中的后端 API。在我前端的一部分中,我是尝试上传要用作新创建博客的图像的图像。当我尝试上传图片时,后端生成的 IFormFile 总是出现在null。以下是代码,非常感谢任何帮助!
new-blog.component.html:
<form [formGroup]="newBlogForm" (ngSubmit)="onSubmit(newBlogForm.value)">
<div>
<label for="Name">
Blog Name
</label>
<input type="text" formControlName="Name">
</div>
<div>
<label for="TileImage">
Tile Image
</label>
<input type="file" formControlName="TileImage">
</div>
<button type="submit">Create Blog</button>
</form>
new-blog.component.ts:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormControl } from '@angular/forms';
import { BlogService } from '../blog-services/blog.service';
@Component({
selector: 'app-new-blog',
templateUrl: './new-blog.component.html',
styleUrls: ['./new-blog.component.css']
})
export class NewBlogComponent implements OnInit {
private newBlogForm: FormGroup;
constructor(private formBuilder: FormBuilder, private blogService: BlogService) { }
ngOnInit() {
this.newBlogForm = this.formBuilder.group({
Name: new FormControl(null),
TileImage: new FormControl(null)
});
}
onSubmit(blogData: FormData) {
console.log('new blog has been submitted.', blogData);
this.blogService.postBlog(blogData);
this.newBlogForm.reset();
}
}
postBlog 来自 blog.service.ts:
postBlog(blogData: FormData): Observable<any> {
const postBlogSubject = new Subject();
this.appOptions.subscribe(
(options) => {
const url = options.blogAPIUrl + '/Blogs';
this.http
.post(url, blogData)
.subscribe(
(blog) => {
postBlogSubject.next(blog);
}
);
}
);
return postBlogSubject.asObservable();
}
我的 BlogController 的签名如下所示:
[HttpPost]
public async Task<ActionResult<Blog>> PostBlog([FromForm]PostBlogModel blogModel)
使用 PostBlogModel 如下:
public class PostBlogModel
{
public string Name { get; set; }
public IFormFile TileImage { get; set; }
}
我已经实现了日志中间件来尝试调试。输出如下(我看到由于某种原因前端正在发送 application/json 而不是 multipart/form-data 但我不确定为什么或如何修复......)
blogapi_1 | info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
blogapi_1 | Request finished in 170.16740000000001ms 500
blogapi_1 | info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
blogapi_1 | Request starting HTTP/1.1 OPTIONS http://localhost:5432/api/v1/Blogs
blogapi_1 | dbug: BlogAPI.Middleware.RequestResponseLoggingMiddleware[0]
blogapi_1 | HTTP Request: Headers:
blogapi_1 | key: Connection, values: keep-alive
blogapi_1 | key: Accept, values: */*
blogapi_1 | key: Accept-Encoding, values: gzip, deflate, br
blogapi_1 | key: Accept-Language, values: en-US,en-IN;q=0.9,en;q=0.8,en-GB;q=0.7
blogapi_1 | key: Host, values: localhost:5432
blogapi_1 | key: Referer, values: http://localhost:5431/blog/new-blog
blogapi_1 | key: User-Agent, values: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
blogapi_1 | key: Origin, values: http://localhost:5431
blogapi_1 | key: Access-Control-Request-Method, values: POST
blogapi_1 | key: Access-Control-Request-Headers, values: content-type
blogapi_1 | key: Sec-Fetch-Site, values: same-site
blogapi_1 | key: Sec-Fetch-Mode, values: cors
blogapi_1 |
blogapi_1 | type:
blogapi_1 | scheme: http
blogapi_1 | host+path: localhost:5432/api/v1/Blogs
blogapi_1 | queryString:
blogapi_1 | body:
blogapi_1 | info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
blogapi_1 | CORS policy execution successful.
blogapi_1 | dbug: BlogAPI.Middleware.RequestResponseLoggingMiddleware[0]
blogapi_1 | HTTP Response: Headers:
blogapi_1 | key: Access-Control-Allow-Headers, values: Content-Type
blogapi_1 | key: Access-Control-Allow-Origin, values: http://localhost:5431
blogapi_1 |
blogapi_1 | statusCode: 204
blogapi_1 | responseBody:
blogapi_1 | info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
blogapi_1 | Request finished in 58.5088ms 204
blogapi_1 | info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
blogapi_1 | Request starting HTTP/1.1 POST http://localhost:5432/api/v1/Blogs application/json 56
blogapi_1 | dbug: BlogAPI.Middleware.RequestResponseLoggingMiddleware[0]
blogapi_1 | HTTP Request: Headers:
blogapi_1 | key: Connection, values: keep-alive
blogapi_1 | key: Content-Type, values: application/json
blogapi_1 | key: Accept, values: application/json, text/plain, */*
blogapi_1 | key: Accept-Encoding, values: gzip, deflate, br
blogapi_1 | key: Accept-Language, values: en-US,en-IN;q=0.9,en;q=0.8,en-GB;q=0.7
blogapi_1 | key: Host, values: localhost:5432
blogapi_1 | key: Referer, values: http://localhost:5431/blog/new-blog
blogapi_1 | key: User-Agent, values: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
blogapi_1 | key: Origin, values: http://localhost:5431
blogapi_1 | key: Content-Length, values: 56
blogapi_1 | key: Sec-Fetch-Site, values: same-site
blogapi_1 | key: Sec-Fetch-Mode, values: cors
blogapi_1 |
blogapi_1 | type: application/json
blogapi_1 | scheme: http
blogapi_1 | host+path: localhost:5432/api/v1/Blogs
blogapi_1 | queryString:
blogapi_1 | body: {"Name":"test","TileImage":"C:\\fakepath\\DSC_0327.jpg"}
【问题讨论】:
-
您是否尝试将包含 Content-Type 标头的 httpOptions 添加到 http.post?
-
看来您正在开发跨域服务。您的浏览器将首先发送一个 HTTP 选项请求并测试返回的标头是否允许它进行真正的提交。在 HTTP 选项测试过程中,您的服务器无法获取该文件。请看:developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
-
@Yeheshuah - 当我尝试添加 Content-Type 标头时,似乎 ASP.NET 核心无法处理输入,它仍然显示来自 Angular 的正文
{"Name":"test","TileImage":"C:\\fakepath\\DSC_0327.jpg"}并且我收到错误 @987654331 @ @Anduin - 是的,这是在 Docker 容器中运行的,但是正如日志显示的那样,看起来 OPTIONS 请求已成功发疯,因为我已经设置了 CORS 策略,因此响应中返回了 Access-Control-Allow-Origin为此。 -
你是如何在你的 post 请求中设置 HttpOptions 的?
-
@AngelaAmarapala 我在上面的 postBlog 函数中添加了以下内容:
let httpOptions: any = { headers: new HttpHeaders({ "Content-Type": "multipart/form-data" }) }; this.http .post(url, blogData, httpOptions)。可能还需要补充一点,当我指定此选项时,似乎没有发出 OPTIONS 请求,它只是直接转到 POST。
标签: c# angular typescript asp.net-core angular8