ASP.NET中Web API解决跨域问题

一、什么是跨域问题

跨域:指的是浏览器不能执行其他网站的脚本。是由浏览器的同源策略造成的,是浏览器施加的安全限制。(服务端可以正常接收浏览器发生的请求,也可以正常返回,但是由于浏览器的安全策略,浏览器不能处理服务端的返回)。

那么什么是同源策略呢?

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

正是由于这个原因,如果是在不同的项目之间进行调用(这里说的调用指的是浏览器调用后端,如果是后端直接调用就不会存在跨域问题)就会被浏览器阻止。WebApi中常见的场景:Web Api作为单独的数据服务层,提供接口供前端界面调用,MVC项目作为显示层,这种情况下如果在MVC的前端界面里面通过ajax调用WebApi的接口,就会存在跨域问题。

二、如何解决跨域问题

网上有很多跨域问题的解决方案,这里就不在一一列举了,下面主要讲解一下在WebApi中如何使用CORS解决跨域问题。CORS全称Cross-Origin Resource Sharing,中文全称是跨域资源共享。CORS解决跨域问题的原理是在http的请求报文和响应报文里面加入响应的标识告诉浏览器能够访问哪些域名的请求。

三、使用代码解决跨域问题

下面结合一个具体的实例来讲解在WebApi里面如何使用CORS解决跨域问题。

1、场景描述

新建两个单独的项目:一个WebApi项目(带有MVC功能,用来提供数据和页面显示),一个MVC项目(只是负责页面显示),项目结构如下图所示:

其中,WebApi项目的端口号是:33982,MVC项目的端口号是:34352(这两个端口号是在本机的地址,在其他电脑上端口号可能不同)。显而易见:两个项目的端口号不同,不属于同源,如果在MVC里面通过前端调用WebApi提供的数据接口,就会出现跨域的问题。

2、项目结构

2.1 WebApi项目结构

新建WebApiController文件夹,用来存放WebApi控制器,并新建一个WebApi控制器,命名为Student。StudentController控制器的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApi.Entity;

namespace WebApi.WebApiController
{
    public class StudentController : ApiController
    {
        public static List<Student> studentList = InitStudentList();

        private static List<Student> InitStudentList()
        {
            return new List<Student>()
            {
               new Student {StudentID =1,StudentName="唐僧",Age=24,Sex="男",Major="师范"},
               new Student {StudentID =2,StudentName="孙悟空",Age=579,Sex="男",Major="管理"},
               new Student {StudentID =3,StudentName="沙悟净",Age=879,Sex="男",Major="水利工程"},
               new Student {StudentID =4,StudentName="白骨精",Age=456,Sex="女",Major="表演"},
               new Student {StudentID =5,StudentName="玉兔精",Age=456,Sex="女",Major="舞蹈"}
            };
        }

        [HttpGet]
        public IHttpActionResult GetAllStudent()
        {
            return Json<List<Student>>(studentList);
        }
    }
}

修改WebApi配置文件类,路由规则里面增加action,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace WebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

新建一个MVC控制器,命名为Student,并添加Index视图,Index视图代码如下:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>测试跨域问题</title>
    <script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
</head>
<body>
    <div style="background-color:#008000;padding:10px;margin:5px;">
        <div style="font-weight:bold;margin-bottom:5px;">Get Student List</div>
        <div style="padding-bottom:5px;">
            <input id="btnGetStudentList" name="btnGetStudentList" type="button" value="Get Student List" />
        </div>
        <div id="students"></div>
    </div>
    <script>
        $('#btnGetStudentList').click(function () {
            $.ajax({
                url: '/api/Student/GetAllStudent',
                type: 'GET',
                dataType: 'json'
            }).success(function (result) {
                DisplayStudentList(result);
            }).error(function (data) {
                alert(data);
            });
        });
        function DisplayStudentList(result) {
            var studentTable = $("<table cellpadding='3' cellspacing='3'></table>");
            var studentTableTitle = $("<tr><th>StudentID</th><th>StudentName</th><th>Age</th><th>Sex</th><th>Major</th></tr>");
            studentTableTitle.appendTo(studentTable);

            for (var i = 0; i < result.length; i++) {
                var studentTableContent = $("<tr><td>"
                    + result[i].StudentID + "</td><td>"
                    + result[i].StudentName + "</td><td>"
                    + result[i].Age + "</td><td>"
                    + result[i].Sex + "</td><td>"
                    + result[i].Major + "</td></tr>"
                );
                studentTableContent.appendTo(studentTable);
            }

            $('#students').html(studentTable);
        }
    </script>
</body>
</html>

2.2 MVC项目结构

MVC项目结构比较简单,新建一个名为Student的控制器,并添加视图,视图如下:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>测试跨域问题</title>
    <script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
</head>
<body>
    <div style="background-color:#008000;padding:10px;margin:5px;">
        <div style="font-weight:bold;margin-bottom:5px;">Get Student List</div>
        <div style="padding-bottom:5px;">
            <input id="btnGetStudentList" name="btnGetStudentList" type="button" value="Get Student List" />
        </div>
        <div id="students"></div>
    </div>
    <script>
        $('#btnGetStudentList').click(function () {
            $.ajax({
                url: 'http://localhost:33982//api/Student/GetAllStudent',
                type: 'GET',
                dataType: 'json'
            }).success(function (result) {
                DisplayStudentList(result);
            }).error(function (data) {
                alert("失败");
            });
        });
        function DisplayStudentList(result) {
            var studentTable = $("<table cellpadding='3' cellspacing='3'></table>");
            var studentTableTitle = $("<tr><th>StudentID</th><th>StudentName</th><th>Age</th><th>Sex</th><th>Major</th></tr>");
            studentTableTitle.appendTo(studentTable);

            for (var i = 0; i < result.length; i++) {
                var studentTableContent = $("<tr><td>"
                    + result[i].StudentID + "</td><td>"
                    + result[i].StudentName + "</td><td>"
                    + result[i].Age + "</td><td>"
                    + result[i].Sex + "</td><td>"
                    + result[i].Major + "</td></tr>"
                );
                studentTableContent.appendTo(studentTable);
            }

            $('#students').html(studentTable);
        }
    </script>
</body>
</html>

四、测试

1、在不做任何处理情况下的测试

先看看同源下的访问情况,直接启动WebApi项目,截图如下:

点击按钮,测试结果如下:

因为是在同一个域中,所以访问没有问题,前端可以正常获取到WebApi返回的数据。下面在来看看在MVC项目中的测试情况。测试截图如下:

从图中可以看出访问失败了,按F12查看访问情况:

从上面的截图中可以看出,发生了跨域访问,浏览器出于安全性的考虑,不能接收返回的数据。

五、使用CORS解决跨域问题

1、安装CORS

在WebApi项目上右键->管理NuGet程序包,然后搜索“microsoft.aspnet.webapi.cors”,选择第一个进行安装

具体的安装过程在这里不再详细解释。

2、配置跨域

在WebApiConfig.cs类中配置跨域,修改后的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Cors;

namespace WebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // 跨域配置
            config.EnableCors(new EnableCorsAttribute("*","*","*"));

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

这里使用“*”号表示对所有的域名都可以跨域。再次从MVC里面访问WebApi,查看测试结果:

从上面的截图中可以看出,这时就可以允许跨域访问了,在Response Headers里面添加了:Access-Control-Allow-Origin:*。

六、CORS参数详解

在上面我们在WebApi的配置文件中使用了:

config.EnableCors(new EnableCorsAttribute("*","*","*"));

这一句代码解决了跨域问题。但是这种“*”号是不安全的。查看MSDN,发现EnableCorsAttribute类有如下的构造函数:

public EnableCorsAttribute(
    string origins,
    string headers,
    string methods
)

详细的参数解释请查看MSDN。

知道了EnableCorsAttribute类的构造函数以后,我们可以使用下面的方法进行改进。

方法一:在Web.Config文件的appSettings节点里面配置参数:

然后修改WebApiConfig.cs文件的Register方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Configuration;

namespace WebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            #region 跨域配置
            string allowedOrigin = ConfigurationManager.AppSettings["allowedOrigin"];
            string allowedHeaders = ConfigurationManager.AppSettings["allowedHeaders"];
            string allowedMethods = ConfigurationManager.AppSettings["allowedMethods"];
            config.EnableCors(new EnableCorsAttribute(allowedOrigin, allowedHeaders, allowedMethods));
            #endregion
            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

方法二:如果只想对某些api或者api里面的某些方法做跨域,可以直接在API控制器类上面使用特性标注或者在方法上面使用特性标注。

允许Student控制器可以跨域:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApi.Entity;
using System.Web.Http.Cors;

namespace WebApi.WebApiController
{
    [EnableCors(origins:"http://localhost:34352",headers:"*",methods:"GET,POST,PUT,DELETE")]
    public class StudentController : ApiController
    {
        public static List<Student> studentList = InitStudentList();

        private static List<Student> InitStudentList()
        {
            return new List<Student>()
            {
             new Student {StudentID =1,StudentName="唐僧",Age=24,Sex="男",Major="师范"},
                new Student {StudentID =2,StudentName="孙悟空",Age=579,Sex="男",Major="管理"},
               new Student {StudentID =3,StudentName="沙悟净",Age=879,Sex="男",Major="水利工程"},
               new Student {StudentID =4,StudentName="白骨精",Age=456,Sex="女",Major="表演"},
               new Student {StudentID =5,StudentName="玉兔精",Age=456,Sex="女",Major="舞蹈"}
            };
        }

        [HttpGet]
        public IHttpActionResult GetAllStudent()
        {
            return Json<List<Student>>(studentList);
        }
    }
}

只允许Student控制器里面的GetAllStudent方法可以跨域:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApi.Entity;
using System.Web.Http.Cors;

namespace WebApi.WebApiController
{

    public class StudentController : ApiController
    {
        public static List<Student> studentList = InitStudentList();

        private static List<Student> InitStudentList()
        {
            return new List<Student>()
            {
             new Student {StudentID =1,StudentName="唐僧",Age=24,Sex="男",Major="师范"},
                new Student {StudentID =2,StudentName="孙悟空",Age=579,Sex="男",Major="管理"},
               new Student {StudentID =3,StudentName="沙悟净",Age=879,Sex="男",Major="水利工程"},
               new Student {StudentID =4,StudentName="白骨精",Age=456,Sex="女",Major="表演"},
               new Student {StudentID =5,StudentName="玉兔精",Age=456,Sex="女",Major="舞蹈"}
            };
        }

        /// <summary>
        /// 允许跨域
        /// </summary>
        /// <returns></returns>
        [EnableCors(origins: "http://localhost:34352", headers: "*", methods: "GET,POST,PUT,DELETE")]
        [HttpGet]
        public IHttpActionResult GetAllStudent()
        {
            return Json<List<Student>>(studentList);
        }

        /// <summary>
        /// 不允许跨域
        /// </summary>
        [HttpPost]
        public void Post()
        { }
    }
}

到此这篇关于ASP.NET中Web API解决跨域问题的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • ASP.net WebAPI跨域调用问题的解决方法

    发现问题 最近在做一个项目,前端是VUE,后端是WebAPI,业务也就是一些实体的增删改查.在项目开始的时候我就预计到有跨域的问题,所以也找了一下资料,在Web.Config里面加上了配置信息: <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-A

  • ASP.NET WebAPI2复杂请求跨域设置的方法介绍

    ASP.Net Core的跨域设置比较简单  官方都整合了 具体的参见微软官方文档: https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.1#ecors 跨域条件 跨域是指的当前资源访问其他资源时发起的http请求由于安全原因(由于同源策略,域名.协议.端口中只要有一个不同就不同源),浏览器限制了这些请求的正常访问,特别需要注意的是这些发生在浏览器中. 解决方法 方法1.web.config文件

  • 支持Ajax跨域访问ASP.NET Web Api 2(Cors)的示例教程

    随着深入使用ASP.NET Web Api,我们可能会在项目中考虑将前端的业务分得更细.比如前端项目使用Angularjs的框架来做UI,而数据则由另一个Web Api 的网站项目来支撑.注意,这里是两个Web网站项目了,前端项目主要负责界面的呈现和一些前端的相应业务逻辑处理,而Web Api则负责提供数据. 这样问题就来了,如果前端通过ajax访问Web Api项目话,就涉及到跨域了.我们知道,如果直接访问,正常情况下Web Api是不允许这样做的,这涉及到安全问题.所以,今天我们这篇文章的主

  • ASP.Net WebAPI与Ajax进行跨域数据交互时Cookies数据的传递

    前言 最近公司项目进行架构调整,由原来的三层架构改进升级到微服务架构(准确的说是服务化,还没完全做到微的程度,颗粒度没那么细),遵循RESTFull规范,使前后端完全分离,实现大前端思想.由于是初次尝试,中途也遇到了不少问题.今天就来讨论一下其中之一的问题,WebAPI与前端Ajax 进行跨域数据交互时,由于都在不同的二级域名下(一级域名相同),导致Cookies数据无法获取. 最开始通过头部(Header)将Cookies传输到其WebAPI,也能解决问题. 下面讲述另外一种解决方案. 解决过

  • asp.net基于JWT的web api身份验证及跨域调用实践

    随着多终端的出现,越来越多的站点通过web api restful的形式对外提供服务,很多网站也采用了前后端分离模式进行开发,因而在身份验证的方式上可能与传统的基于cookie的Session Id的做法有所不同,除了面临跨域提交cookie的烦人问题外,更重要的是,有些终端可能根本不支持cookie. Json Web Token(jwt)是一种不错的身份验证及授权方案,简单的说就是调用端调用api时,附带上一个由api端颁发的token,以此来验证调用者的授权信息. 但由于时间关系,不对jw

  • asp.net core webapi 服务端配置跨域的实例

    在前后端分离开发中服务端仅仅只为前端提供api接口,并且前后端往往单独部署,此时就会出现浏览器跨域问题.asp.net core提供了简单优雅的解决方案. 在startup文件的Configure添加如下代码(替换"http://localhost:8080"为你的前端部署地址,此处测试的前端地址为本地的8080端口) 注:asp.net core2.0以下需安装nuget包:Microsoft.AspNetCore.Cors app.UseCors(builder => { b

  • ASP.NET中Web API解决跨域问题

    一.什么是跨域问题 跨域:指的是浏览器不能执行其他网站的脚本.是由浏览器的同源策略造成的,是浏览器施加的安全限制.(服务端可以正常接收浏览器发生的请求,也可以正常返回,但是由于浏览器的安全策略,浏览器不能处理服务端的返回). 那么什么是同源策略呢? 同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS.CSFR等攻击.所谓同源是指"协议+域名+端口"

  • ASP.NET中Web API的简单实例

    一.Web API的路由 1.在Visual Studio中新建MVC4项目,在App_Start目录下有一个WebApiConfig.cs文件,这个文件中就是相应的Web API的路由配置了. 2.Web API 框架默认是基于 Restful 架构模式的,与ASP.NET MVC 有区别的是,它会根据 Http 请求的 HttpMethod(Get.Post.Put.Delete)来在Controller 中查找 Action,规则是:Action 名中是否以Get.Post 开头?Acti

  • ASP.NET中Web API的参数绑定

    在这篇文章中,我们将学习WebAPI如何将HTTP请求数据绑定到一个操作方法的参数中. 操作方法在WebAPI控制器中可以有一个或多个不同类型的参数.它可以是基本数据类型或复杂类型.WebAPI根据URL的查询字符串或请求主体中参数类型来绑定操作方法的参数. 如果参数类型是基本数据类型(int,double,string,DateTime,bool等),WebAPI默认将会从URL中获取参数值(即通过querystring)获取. 如果参数类型的复杂类型,WebAPI默认从请求主体中获取参数值.

  • Vue项目中该如何解决跨域问题

    目录 跨域 同源策略 express服务器 vue处理跨域 express处理跨域 总结 跨域 跨域报错是前端开发中非常经典的一个错误,报错如下 Access to XMLHttpRequest at '......' from origin  '......' has been blocked by CORS policy:  No 'Access-Control-Allow-Origin' header is present on the requested resource. 跨域错误源自

  • vue项目打包后怎样优雅的解决跨域

    前言 在使用vue.js开发前端项目时,再结合webpack搞起各种依赖.各种插件进行开发,无疑给前端开发带来了很多便捷,就在解决跨域这个问题上,相信众多用vue.js的前端同僚们同我一样尝到了甜头,开发环境全靠proxyTable一通配置简直不要太酸爽.还不明所以然的新手们可能还没搞清我说的是什么,就是下面这几行配置: proxyTable: { '/api': { target: 'http://113.113.113.113:5000', //假的接口地址哈 changeOrigin: t

  • 使用Flask和Django中解决跨域请求问题

    Flask解决跨域 1.下载flask_cors包 pip install flask-cors 2.使用flask_cors的CORS 代码示例 from flask_cors import * app = Flask(__name__) CORS(app, supports_credentials=True) Flask-CORS文档: https://flask-cors.readthedocs.io/en/latest/ Django解决跨域 1.安装django-cors-header

  • ASP.NET配合jQuery解决跨域调用的问题

    一. 使用JSONp方式调用 不做详细讲解,可以参考jq文档<jQuery 1.10.3 在线手册> 二. 服务端配置 修改Web.config 文件 <system.webServer> <modules runAllManagedModulesForAllRequests="true"></modules> <httpProtocol> <customHeaders> <add name="Ac

  • python web.py开发httpserver解决跨域问题实例解析

    使用web.py做http server开发时,遇到postman能够正常请求到数据,但是浏览器无法请求到数据,查原因之后发现是跨域请求的问题. 跨域请求,就是在浏览器窗口中,和某个服务端通过某个 "协议+域名+端口号" 建立了会话的前提下,去使用与这三个属性任意一个不同的源提交了请求,那么浏览器就认为你是跨域了,违反了浏览器的同源策略. w3c标准中,有针对跨域请求的规范,在响应头中有以下三种跨域访问限制: Access-Control-Allow-Origin:限制允许跨域访问的源

  • vue中axios解决跨域问题和拦截器的使用方法

    vue中axios不支持vue.use()方式声明使用. 所以有两种方法可以解决这点: 第一种: 在main.js中引入axios,然后将其设置为vue原型链上的属性,这样在组件中就可以直接 this.axios使用了 import axios from 'axios'; Vue.prototype.axios=axios; components: this.axios({ url:"a.xxx", method:'post', data:{ id:3, name:'jack' } }

  • Webpack devServer中的 proxy 实现跨域的解决

    Webpack dev server使用http-proxy解决跨域问题 文档资料 webpack关于webpack-dev-server开启proxy的官方介绍 Vue-cli proxyTable 解决开发环境的跨域问题--虽然这篇是写vue的,不过用在webpack-dev-server上也是一样的 http-proxy-middleware--webpack-dev-server的实现方法其实是对这个的封装 配置http-proxy 在webpack的配置文件(webpack.confi

随机推荐