Blazor WebAssembly中GetAsync调用失败及CORS问题求助
从WinForms转Blazor WASM调用WCF API的CORS问题
我从Windows Forms转做Blazor WebAssembly开发,尝试调用一个已确认可正常向其他应用提供数据的WCF API获取数据。最初在页面加载的OnInitializedAsync方法中调用httpClient.GetAsync时直接崩溃,跟着教程改用IHttpClientFactory更新代码后,现在浏览器报CORS错误:请求被CORS策略阻止,目标资源不存在Access-Control-Allow-Origin头。这个API是十年前开发的WCF服务,想咨询实现CORS的最佳方式,是否需要重写API?
初始服务类代码
public class RecipeService : IRecipeService { private readonly HttpClient httpClient; private string baseURL = clConstants.SERVER_PATH; private string apiEndPoint = "getRecipeByID/"; public RecipeService(HttpClient httpClient) { this.httpClient = httpClient; } async Task<List<clRecipe>> IRecipeService.getRecipeByID(int id) { ConfigureHTTPClient(); string URL = clConstants.SERVER_PATH + apiEndPoint + id.ToString(); // 此行代码崩溃 var res = httpClient.GetAsync(URL).Result; } }
更新后服务类及接口代码
public class RecipeService : IRecipeService { private readonly string apiEndPoint = "GetRecipeByID/"; private readonly IHttpClientFactory httpClientFactory; private HttpClient CreateHttpClient() => httpClientFactory.CreateClient("MainApi"); private readonly JsonSerializerOptions jsonOptions = new() { PropertyNameCaseInsensitive = true }; public RecipeService(IHttpClientFactory httpClientFactory) { this.httpClientFactory = httpClientFactory; } public async Task<List<clRecipe>>getRecipeByID(int id) { string URL = apiEndPoint + id.ToString(); var response = await CreateHttpClient().GetAsync(URL, HttpCompletionOption.ResponseHeadersRead); var result = await response.Content.ReadAsStreamAsync(); var recipe = await JsonSerializer.DeserializeAsync<List<clRecipe>>(result, jsonOptions); return recipe; } } public interface IRecipeService { Task<List<clRecipe>> getRecipeByID(int id); }
Program.cs配置
builder.Services.AddHttpClient("MainApi", options => { options.BaseAddress = new Uri(clConstants.SERVER_PATH); }); builder.Services.AddSingleton<IRecipeService, RecipeService>();
页面代码
@inject IRecipeService RecipeService private List<clRecipe> recipe { get; set; } public interface IRecipeService { Task<List<clRecipe>> getRecipeByID(int id); }
当前错误信息
请求被CORS策略阻止:请求的资源上不存在'Access-Control-Allow-Origin'头。如果不需要获取响应内容,可将请求模式设置为'no-cors'以禁用CORS获取资源。
解决方案:无需重写API的CORS实现方式
1. 在WCF服务端直接配置CORS
对于WCF服务,有两种可靠的添加CORS支持的方式:
- 自定义MessageInspector拦截响应:实现
IDispatchMessageInspector接口,在返回响应时注入CORS头:
public class CorsMessageInspector : IDispatchMessageInspector { public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { return null; } public void BeforeSendReply(ref Message reply, object correlationState) { var httpResponse = reply.Properties["httpResponse"] as HttpResponseMessageProperty; if (httpResponse != null) { // 生产环境建议替换为具体允许的域名,不要用* httpResponse.Headers.Add("Access-Control-Allow-Origin", "*"); httpResponse.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); httpResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type"); } } }
之后在WCF的配置文件或代码中注册该Inspector即可生效。
- IIS托管下添加HTTP模块:如果WCF部署在IIS上,可在web.config中添加自定义HTTP模块,全局注入CORS头:
<system.webServer> <modules runAllManagedModulesForAllRequests="true"> <add name="CorsModule" type="YourNamespace.CorsHttpModule"/> </modules> </system.webServer>
实现IHttpModule接口,在请求处理环节添加CORS头。
2. 使用反向代理(推荐生产环境)
如果不想修改WCF服务的代码或配置,可通过反向代理规避跨域问题:
- Blazor Hosted模式集成Yarp反向代理:在Blazor Server项目中配置Yarp,将WCF API的请求转发到目标服务,浏览器仅与Blazor Server通信,避免跨域:
// Program.cs builder.Services.AddReverseProxy() .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
// appsettings.json "ReverseProxy": { "Routes": { "wcf-route": { "ClusterId": "wcf-cluster", "Match": { "Path": "/wcf/{**catch-all}" } } }, "Clusters": { "wcf-cluster": { "Destinations": { "wcf-service": { "Address": "http://你的WCF服务地址/" } } } } }
之后Blazor服务中调用/wcf/GetRecipeByID/{id}即可。
- IIS ARR反向代理:在IIS中安装Application Request Routing,配置转发规则,将Blazor域名下的特定路径转发到WCF服务,同样可解决跨域问题。
3. 开发环境临时方案
仅用于本地测试,可使用浏览器插件(如Chrome的CORS Unblock)临时禁用CORS检查,但绝对禁止用于生产环境。
结论
不需要重写WCF API,优先选择在WCF端配置CORS或使用反向代理方案,这两种方式成本远低于重写,且能稳定解决跨域问题。
内容的提问来源于stack exchange,提问作者Steven Marcus
相关产品推荐
相关产品推荐

