在现代的Web应用程序开发中,跨域资源共享(Cross-Origin Resource Sharing, CORS)问题是开发者经常遇到的一个挑战。特别是当前端和后端服务部署在不同的域名或端口时,CORS问题就会显得尤为突出。在这篇博客中,我们将深入探讨如何在
.NET WebService
中解决CORS问题,帮助开发者顺利实现跨域请求。
一、CORS问题描述
在Web应用中,浏览器安全机制通常会阻止来自不同域的请求,这被称为“同源策略”。同源策略允许同一来源(协议、主机和端口相同)的资源相互访问,但会阻止不同来源的资源访问。这种机制虽然提高了安全性,但在实际开发中,前端和后端通常会部署在不同的服务器上,这就引发了CORS问题。
举个例子,当你试图从
http://frontend.com
发送一个请求到
http://api.backend.com
时,浏览器会拦截这个请求并抛出一个CORS错误:
Access to XMLHttpRequest at 'http://api.backend.com/resource' from origin 'http://frontend.com' has been blocked by CORSpolicy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
对于
.NET WebService
,如果前端应用尝试从另一个域名访问服务,而服务端没有适当的CORS策略,那么浏览器会阻止这些请求并显示该跨域错误。
二、CORS问题代码示例
为了更好地理解CORS问题及其解决方案,让我们先创建一个简单的前后端交互的
.NET WebService
示例。
1. 后端WebService接口代码
首先,创建一个新的
.NET Framework
项目。你可以使用
Visual Studio
或者命令行工具(如
dotnet CLI
)来创建项目。在项目中,我们定义一个
.asmx
文件,并在
.asmx.cs
文件里创建一个接口。
接口代码如下:
usingNewtonsoft.Json;usingSystem;usingSystem.Collections.Generic;usingSystem.Data;usingSystem.Web;usingSystem.Web.Services;namespaceTestProject{[WebService(Namespace ="http://tempuri.org/")][WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)][System.ComponentModel.ToolboxItem(false)][System.Web.Script.Services.ScriptService]publicclassTest:WebService{[WebMethod]publicvoidGetJsonData(){string json ="{\"MapPoints\":[{\"Coordinates\":[\"118.87220827635\",\"34.885061248714\"],\"Speed\":\"45.7\",\"Time\":\"2024-05-13T13:02:09\"}]}";
HttpContext.Current.Response.ContentType ="application/json";
HttpContext.Current.Response.Write(json);}}}
这个控制器有一个GET方法,当请求
http://localhost:80/Test.asmx/GetJsonData
时,它会返回一个串JSON数据。
这里我们可以用 Postman 测试代码,正确返回结果,则验证后端接口代码没有问题。
2. 前端接口请求代码
这里我使用的前端访问接口的JavaScript代码是基于
axios
实现的。
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>CORS Test</title></head><body><h1>CORS Test</h1><buttonid="fetchDataButton">Fetch Data</button><scriptsrc="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>
document.getElementById('fetchDataButton').addEventListener('click',function(){getCarLocation();});functiongetCarLocation(){
axios.get('http://localhost:80/Test.asmx/GetJsonData').then(function(response){
console.log('Success:', response.data);}).catch(function(error){
console.error('Error:', error);});}</script></body></html>
页面效果图如下:
当点击
Fetch Data
按钮时,页面会访问
http://localhost:80/Test.asmx/GetJsonData
接口,并输出返回值到F12控制台日志里。
此时,如果我们不配置CORS,那么请求会被拦截,并报错:
Access to XMLHttpRequest at 'http://localhost:80/Test.asmx/GetJsonData' from origin 'http://localhost:8080' has been blocked by CORSpolicy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
三、CORS配置详细步骤
为了让我们的
WebService
支持跨域请求,我们需要在项目中配置CORS。在
.NET Framework
中,我们可以通过如下步骤来配置CORS。
1. 配置Global.asax全局请求头参数
创建或打开项目的
Global.asax
文件,找到或添加
Application_BeginRequest()
方法,添加响应头参数,其中
<"Access-Control-Allow-Origin", "*">
这个响应头是最重要的。
namespaceTestProject{publicclassGlobal:System.Web.HttpApplication{protectedvoidApplication_BeginRequest(){
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers","Content-Type, Accept, Authorization, X-Requested-With");if(HttpContext.Current.Request.HttpMethod =="OPTIONS"){
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age","86400");
HttpContext.Current.Response.StatusCode =204;
HttpContext.Current.Response.End();}}}}
要非常注意的是,每个请求头参数只能添加一次,如果重复添加,依然会访问报错,可以排查一下
web.config
文件或者专门的路由模块有没有已经添加,或者再每次添加之前判断当前请求头是否已经存在,如果存在删除在添加。
2. 创建自定义HTTP模块并注册
在
.NET Framework
中,通过自定义 HTTP 模块修改 HTTP 响应头,可以协助处理跨域问题。
我们右键解决方案,新建项目,创建
CustomHttpModules
模块。
模块内创建
HeaderFilterHttpModule.cs
文件。
代码如下 :
usingSystem;usingSystem.Web;namespaceCustomHttpModules{publicclassHeaderFilterHttpModule:IHttpModule{publicvoidInit(HttpApplication context){
context.PreSendRequestHeaders += OnPreSendRequestHeaders;}publicvoidDispose(){}voidOnPreSendRequestHeaders(object sender,EventArgs e){try{HttpApplication app = sender asHttpApplication;if(app !=null&& app.Context !=null&& app.Context.Response !=null){var headers = app.Context.Response.Headers;if(headers !=null){
headers.Remove("Server");
headers.Remove("X-AspNet-Version");
headers.Remove("X-AspNetMvc-Version");
headers.Remove("X-Frame-Options");
headers.Remove("X-Powered-By");// 添加CORS相关的头信息
headers.Add("Access-Control-Allow-Origin","*");
headers.Add("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS");
headers.Add("Access-Control-Allow-Headers","Content-Type, Accept");}}}catch(Exception ex){// 记录异常}}}}
创建完成后,我们到主项目注册这个自定义的 HTTP 模块。
打开
web.config
文件,找到
<configuration>
下的
<system.webServer>
标签,引入我们刚刚创建好的
HeaderFilterHttpModule
模块。
<configuration><system.webServer><modules><addname="HeaderFilterHttpModule"type="CustomHttpModules.HeaderFilterHttpModule"/></modules></system.webServer></configuration>
3. 测试增加CORS配置后的代码
添加上述有关CORS的配置后,我们重新启动
.NET Framework
项目,通过测试页面点击
Fetch Data
按钮,给
http://localhost:80/Test.asmx/GetJsonData
接口发送请求。
可以看到我们得到了正确的返回值。
{"MapPoints":[{"Coordinates":["118.87220827635","34.885061248714"],"Speed":"45.7","Time":"2024-05-13T13:02:09"}]}
.NET WebService
跨域CORS问题完美解决。
四、CORS问题解决总结
通过配置
global.asax
全局文件,创建和注册自定义 HTTP 模块,我们成功地解决了
.NET WebService
中的 CORS 问题。这种方法的关键在于拦截和修改 HTTP 响应头,添加必要的 CORS 头信息。总结如下:
- 修改Global.asax文件:修改
Application_BeginRequest
方法,修改全局请求头参数。 - 创建自定义 HTTP 模块:实现
IHttpModule
接口,并在PreSendRequestHeaders
事件中添加或移除 HTTP 头信息。 - 注册 HTTP 模块:在
Web.config
文件中注册自定义的 HTTP 模块。 - 测试能否跨域:通过前端发送跨域请求来验证 CORS 配置是否正确。
通过这些步骤,开发者可以有效地解决跨域资源共享问题,确保前后端服务的顺畅通信。在实际开发中,根据具体项目的需求,CORS 配置可能会有所不同,但核心思想和步骤是类似的。希望这篇博客能为你解决 CORS 问题提供有价值的帮助。
版权归原作者 Damon小智 所有, 如有侵权,请联系我们删除。