在现代的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 cors policy: 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
文件里创建一个接口。
接口代码如下:
using newtonsoft.json;
using system;
using system.collections.generic;
using system.data;
using system.web;
using system.web.services;
namespace testproject
{
[webservice(namespace = "http://tempuri.org/")]
[webservicebinding(conformsto = wsiprofiles.basicprofile1_1)]
[system.componentmodel.toolboxitem(false)]
[system.web.script.services.scriptservice]
public class test : webservice
{
[webmethod]
public void getjsondata()
{
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
实现的。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cors test</title>
</head>
<body>
<h1>cors test</h1>
<button id="fetchdatabutton">fetch data</button>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
document.getelementbyid('fetchdatabutton').addeventlistener('click', function () {
getcarlocation();
});
function getcarlocation() {
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 cors policy: 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", "*">
这个响应头是最重要的。
namespace testproject
{
public class global : system.web.httpapplication
{
protected void application_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
文件。
代码如下 :
using system;
using system.web;
namespace customhttpmodules
{
public class headerfilterhttpmodule : ihttpmodule
{
public void init(httpapplication context)
{
context.presendrequestheaders += onpresendrequestheaders;
}
public void dispose()
{ }
void onpresendrequestheaders(object sender, eventargs e)
{
try
{
httpapplication app = sender as httpapplication;
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>
<add name="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 问题提供有价值的帮助。
发表评论