首页 技术 正文
技术 2022年11月12日
0 收藏 583 点赞 4,300 浏览 8482 个字

Ajax跨域问题及解决方案

 

目录

复现Ajax跨域问题

  • 做两个简单的小项目复现Ajax跨域问题. 后端语言使用Java
  • 首先是一个简单的订单系统, 通过访问/loadOrderList, 最终以json串形式返回订单集合. 该项目使用Tomcat发布在7070端口.
@RequestMapping("/loadOrderList")@ResponseBodypublic List<Order> loadOrderList(String uid){    //模拟订单数据    Order o1 = new Order();    o1.setId("111");    o1.setTotal(333.33);    o1.setDate("2019-4-29");    Order o2 = new Order();    o2.setId("222");    o2.setTotal(444.44);    o2.setDate("2019-5-29");    Order o3 = new Order();    o3.setId("333");    o3.setTotal(555.55);    o3.setDate("2019-6-29");    List<Order> list = new ArrayList<>();    list.add(o1);    list.add(o2);    list.add(o3);    return list;}
  • 在另一个项目中做一个向订单系统发送一个ajax请求, 获取订单集合. 该项目使用Tomcat插件发布在9090端口.
//index.jsp<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>Title</title>    <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.js"></script>    <script type="text/javascript">        function sendAjax() {            $.post("http://localhost:7070/order/loadOrderList", "uid=1234", function (data) {                alert(data);            });        }    </script></head><body>    <a href="javascript:sendAjax()" rel="external nofollow"  rel="external nofollow" >sendAjax</a></body></html>
  • 点击sendAjax超链接向订单系统发送ajax请求.
    Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)
  • 通过开发者工具发现虽然服务器以状态码200响应回来, 但是控制台却报错了.
    Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)
    Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)
  • 这就是Ajax跨域出错的一种表现, 下面分析原因.

Ajax跨域介绍

  • Ajax跨域问题是由浏览器的同源策略造成的, 首先要理解这个概念.
  • 我们可以通过协议+域名+端口确定一个源. 在上面的示例中, 你可以把一个项目理解为一个源. Ajax请求可以对源内的资源发起访问, 但是不同源之间进行Ajax就会有问题.
  • 当向不同源的资源发起Ajax请求时, 浏览器会加上Origin字段来标识源
Accept: */*Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Connection: keep-aliveContent-Length: 8Content-Type: application/x-www-form-urlencoded; charset=UTF-8Host: localhost:7070Origin: http://localhost:9090   协议+域名+端口
  • 服务器会根据Origin字段决定是否同意这次请求, 如果Origin指定的源不在许可范围内, 服务器会返回一个不带有Access-Control-Allow-Origin字段的响应. 浏览器解析时发现缺少了这个字段, 就会报错. 这种错误不能通过状态码识别, 因为状态码很有可能就是200(见上面的案例).

Ajax跨域解决方案

  • 下面介绍最常用Ajax跨域解决方案.

一. 在服务端添加响应头Access-Control-Allow-Origin

  • 既然我们已经知道了Ajax跨域失败是因为响应中缺少了响应头Access-Control-Allow-Origin, 那么就想办法加上去.
  • 以Java项目为例, 在后端我们使用CORSFilter过滤器加上该响应头.
  • (假设是Maven项目), 首先在pom.xml中添加坐标
<dependency>    <groupId>com.thetransactioncompany</groupId>    <artifactId>cors-filter</artifactId>    <version>2.5</version>    <scope>runtime</scope></dependency>
  • 然后在web.xml中对过滤器进行配置.
    <filter>        <filter-name>CORS</filter-name>        <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>        <init-param>            <param-name>cors.allowOrigin</param-name><!--这个标签是关键, *代表所有源都能访问-->            <param-value>*</param-value>        </init-param>        <init-param>            <param-name>cors.supportedMethods</param-name>            <param-value>GET, POST, HEAD, PUT, DELETE</param-value>        </init-param>        <init-param>            <param-name>cors.supportedHeaders</param-name>            <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value>        </init-param>        <init-param>            <param-name>cors.exposedHeaders</param-name>            <param-value>Set-Cookie</param-value>        </init-param>        <init-param>            <param-name>cors.supportsCredentials</param-name>            <param-value>true</param-value>        </init-param>    </filter>    <filter-mapping>        <filter-name>CORS</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>
  • 配置后重启订单项目, 再次发起Ajax请求可以看到成功返回数据, 响应头中包含了Access-Control-Allow-Origin, 值为发起Ajax请求的源.
    Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)
    Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)

二. 使用JSONP解决

  • 上面直接通过过滤器添加响应头的方法可以说是对症下药, 那么还有没有什么偏方呢?
  • 还真的有. 在jsp文件中经常通过通过<script>标签引入一段js代码, 这段代码通常来源于网络, 也就是不同源. 那么我们不妨通过<srcipt>标签完成Ajax请求, 这样便顺带解决了跨域问题.
  • 下面还是沿用上面的案例进行演示.
  • 我们对发送ajax的jsp进行修改
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>Title</title>    <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.js"></script>    <script>        function doCallBack(data){            var str = JSON.stringify(data);            alert(str);        }    </script></head><body>    <script src="http://localhost:7070/order/loadOrderList3?uid=111&callBack=doCallBack"></script></body></html>
  • 上面的代码中, 我们首先定义了doCallBack()函数, 它接收一个字符串参数, 并且会把接收到的字符串显示出来.
  • 然后在<body>标签中编写<script>标签, 我们将通过<script>标签请求订单系统, 订单系统将会返回一段js代码, 这段js代码会调用doCallBack()方法.
  • 为了能够拼接出doCallBack(字符串参数...)js代码, 我们在订单系统中作如下操作.
@RequestMapping("/loadOrderList3")@ResponseBodypublic String loadOrderList3(String uid, String callBack){    //模拟订单数据    Order o1 = new Order();    o1.setId("111");    o1.setTotal(333.33);    o1.setDate("2019-4-29");    Order o2 = new Order();    o2.setId("222");    o2.setTotal(444.44);    o2.setDate("2019-5-29");    Order o3 = new Order();    o3.setId("333");    o3.setTotal(555.55);    o3.setDate("2019-6-29");    List<Order> list = new ArrayList<>();    list.add(o1);    list.add(o2);    list.add(o3);    //拼接js代码    String result = callBack + "(" + JSON.toJSONString(list) + ")";    return result;}
  • 这个想法是不是很妙? 明白这个原理之后, 我们可以使用jQuery方便进行JSONP操作, 在上面的代码中我们人为指定了一个名为doCallBack的函数, 而jQuery会随机用时间戳生成一个函数名, 原理和上面是一样的.
  • 所以完成一开时点击超链接发送Ajax请求只需要如下几步.
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>Title</title>    <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.js"></script>    <script>        function sendAjax(){            $.getJSON("http://localhost:7070/order/loadOrderList3?callBack=?","uid=111",            function (data) {                var str = JSON.stringify(data);                alert(str);            });        }    </script></head><body>    <a href="javascript:sendAjax()" rel="external nofollow"  rel="external nofollow" >sendAjax</a></body></html>

小结

  • 上面两种解决办法在思路上有着本质的不同. 方案一抓住CORS跨域访问问题的本质, 在后端加上响应头解决跨域问题. 方案二JSONP利用的是<script>标签能够跨域获取js代码的特性, 绕过跨域问题.

asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)

 

这篇文章介绍如何允许跨域访问

浏览器安全不允许不同域名的网页之间发送请求。这种限制叫做同源策略(the same-origin policy)。

同源策略可以防止一个恶意的站点读取另一个站点的敏感数据。

有时候,你想允许网站发送跨域的请求到你的应用。

Cross Origin Resource Sharing ( CORS ) :

  • 是一个W3C的标准;即允许放宽同源策略
  • 不是一个安全的功能,CORS 放宽了安全性。允许跨域,会让API更不安全
  • 允许一个服务明确的允许一些跨域请求,而拒绝另外一些
  • 比早些的技术(例如JSONP)更安全,更灵活

1.那么同源指的是什么呢

如果两个URLs是同源的,那么它们有相同的协议,主机(域名),端口

下面两个是同源的URLs:

  • https://example.com/foo.html
  • https://example.com/bar.html

下面的这些相比于前面的两个URL,有不同的源:

  • https://example.net – Different domain 不同的域名
  • https://www.example.com/foo.html – Different subdomain 不同的子域名
  • http://example.com/foo.html – Different scheme  不同的协议
  • https://example.com:9000/foo.html – Different port    不同的端口号

IE浏览器考虑同源问题的时候,不会考虑端口号

2.带策略的CORS 和中间件

CORS中间件处理跨域请求。下面的代码允许指定的源能对整个应用进行跨域请求

Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)

public class Startup{    public Startup(IConfiguration configuration)    {        Configuration = configuration;    }    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";    public IConfiguration Configuration { get; }    public void ConfigureServices(IServiceCollection services)    {     //AddCors方法的调用会把CORS服务加到应用的服务容器中(service container);        services.AddCors(options =>        {            options.AddPolicy(MyAllowSpecificOrigins,            builder =>            {                builder.WithOrigins("http://example.com",   //CorsPolicyBuilder方法可以链式调用方法,                                    "http://www.contoso.com");            });        });        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);    }    public void Configure(IApplicationBuilder app, IHostingEnvironment env)    {        if (env.IsDevelopment())        {            app.UseDeveloperExceptionPage();        }        else        {            app.UseHsts();        }        app.UseCors(MyAllowSpecificOrigins);    //这个代码会把CORS策略通过CORS中间件应用到这个应用的所有终端(endpoints);即把跨域作用到整个应用        //注意:1.UseCors必须在UseMvc之前被调用;2. URL末尾不能加/ ;这个url指的是 builder.WithOrigins(url)中的url
        app.UseHttpsRedirection();        app.UseMvc();    }}

Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)

这段代码做了下面的操作

  • 设置策略名为_myAllowSpecificOrigins,这个名字是随意取的
  • 调用UseCors 扩展方法来允许跨域
  • 调用带有lambda表达式的 AddCors 方法。lambda表达式取得一个 CorsPlicyBuild对象,进行一些设置

CorsPolicyBuilder方法可以链式调用方法:

builder.WithOrigins("http://example.com",                                "http://www.contoso.com")                                .AllowAnyHeader()                                .AllowAnyMethod();

测试跨域

3.使用[EnableCors]属性设置允许跨域

[EnableCors]属性提供了另一种方式设置跨域。即可以只设置选择的终端,而不是所有的终端.

这里不同于上面的那种方式,上面的方式是应用的所有终端都会被设置允许跨域;

而这里只是设置了[EnableCors]属性的终端;

使用[EnableCors]来指定默认的策略,而[EnableCors(“{Policy String}”)] 指定了特定的策略;

[EnableCors]属性应用于:

  • Razor Page PageModel
  • Controller
  • Controller action method

你可以使用[EnableCors]属性应用不同的策略到 controller/page-model/action 中;

当[EnableCors]属性应用到 controller/page-model/action ,并且CORS在中间件被允许了(指【Enable(“{Policy String}”)】的方式),这两种策略就都被使用了;

不推荐结合使用策略;使用[EnableCors]属性或者中间件,而不是在相同的应用中使用两个

下面的代码给每个方法使用了一种策略

Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)

[Route("api/[controller]")][ApiController]public class WidgetController : ControllerBase{    // GET api/values    [EnableCors("AnotherPolicy")]    [HttpGet]    public ActionResult<IEnumerable<string>> Get()    {        return new string[] { "green widget", "red widget" };    }    // GET api/values/5    [EnableCors]        // Default policy.    [HttpGet("{id}")]    public ActionResult<string> Get(int id)    {        switch (id)        {            case 1:                return "green widget";            case 2:                return "red widget";            default:                return NotFound();        }    }}

Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)

下面的代码创建了一个跨越默认策略和一个名字叫“AnotherPolicy”的策略:

Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)

public class StartupMultiPolicy{    public StartupMultiPolicy(IConfiguration configuration)    {        Configuration = configuration;    }    public IConfiguration Configuration { get; }    public void ConfigureServices(IServiceCollection services)    {        services.AddCors(options =>        {            options.AddDefaultPolicy(                builder =>                {                    builder.WithOrigins("http://example.com",                                        "http://www.contoso.com");                });            options.AddPolicy("AnotherPolicy",                builder =>                {                    builder.WithOrigins("http://www.contoso.com")                                        .AllowAnyHeader()                                        .AllowAnyMethod();                });        });        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);    }    public void Configure(IApplicationBuilder app, IHostingEnvironment env)    {        if (env.IsDevelopment())        {            app.UseDeveloperExceptionPage();        }        else        {            app.UseHsts();        }        app.UseHttpsRedirection();        app.UseMvc();    }}

Ajax跨域问题及解决方案  asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS)   c#中的Cache缓存技术   C#中的Cookie   C#串口扫描枪的简单实现   c#Socket服务器与客户端的开发(2)

另,其实还有[DisableCors]属性可以禁止CORS,这里先暂时不做讲解

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,487
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,903
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,736
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,486
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,126
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,287