AJAX跨域完全讲解

今天在慕课网上学习了AJAX跨域完全讲解:https://www.imooc.com/learn/947

我在收集AJAX面试题的时候其实就已经有过AJAX跨域的问题的了,当时候知道了为什么会存在跨域,以及跨域解决的方案有哪些,今天随着课程的学习,又加深了AJAX跨域的理解,以此记录下来。

为什么会发生产生跨域问题?

上面的图也很清晰了,因为浏览器为了安全(同源),本身就限制了。

  • 当我们发送XMLHttpRequest请求的时候,如果请求的是别的域(主机域名、端口)不同时,那么就会产生跨域问题(客户端无法获取服务端返回的数据)

值得注意的是:跨域的问题是发生在XMLHttpRequest请求的,也就是说,不是XMLHttpRequest请求是不会有跨域问题的

  • 举个很简单的例子:在编写网页的时候,<img = src = www.xxxx.xxxx/ >,URL不是本域的还是可以正常获取该图片的

解决跨域问题的思路

明显地,跨域的问题是由于浏览器限制的,是XMLHttpRequest才会发生的,那么我们可以以这个思路去找找解决思路:

对于浏览器的问题,可以使用相关的参数进行启动浏览器,是可以解决跨域的问题,但是通用性是极低的,了解即可。

JSONP解决跨域

JSONP是JSON使用的一种补充方式,不是官方的协议。JSONP是一种解决跨域问题的一种协议

JSONP这种解决方案其实现在已经很少用了(复杂一点,需要修改后台代码),但我们可以适当了解一下。

使用步骤

在后端增加一个控制器,继承AbstractJsonpResponseBodyAdvice类,完整代码如下:


@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { public JsonpAdvice() {
// TODO Auto-generated constructor stub
super("callback2");
}
}

前端ajax请求:



// 服务器返回的结果
var result; $.ajax({
url: base +"/get1",
dataType: "jsonp",
jsonp: "callback2", //是否需要缓存,如果这里没有配置缓存,那么请求的URL还会有一个参数
cache:true,
success: function(json){
result = json;
}
});

注意的是,前端AJAX的jsonp: "callback2",要和我们的Controllersuper("callback2");是一致的,不然是不会有效的。

JSONP原理是动态创建script来进行请求的:

JSONP的弊端:

  • 要对服务器的代码进行改动
  • 只支持GET方法(原理是动态创建script来进行请求的)
  • 发送的不是XMLHttpRequest请求(XMLHttpRequest请求有很多好用的特性)

参考资料:

CORS解决跨域问题

CORS解决跨域问题(也就是我们服务端被调用方解决跨域的思路)

对于CORS是怎么理解的,我就直接摘抄一下:https://segmentfault.com/a/1190000012469713#articleHeader8的了。

在Java中,我们写下面这个过滤器,就可以完全解决跨域的问题了:



package com.imooc;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.tomcat.util.buf.StringUtils; public class CrosFilter implements Filter { @Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub } @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub HttpServletResponse res = (HttpServletResponse) response; HttpServletRequest req = (HttpServletRequest) request; //带cookie的时候,origin必须是全匹配,不能使用*
String origin = req.getHeader("Origin");
if (!org.springframework.util.StringUtils.isEmpty(origin)) {
res.addHeader("Access-Control-Allow-Origin", origin);
}
res.addHeader("Access-Control-Allow-Methods", "*"); // 支持所有自定义头和预检命令(非简单请求会有预检命令)
String headers = req.getHeader("Access-Control-Request-Headers");
if (!org.springframework.util.StringUtils.isEmpty(headers)) {
res.addHeader("Access-Control-Allow-Headers", headers);
} res.addHeader("Access-Control-Max-Age", "3600");
// enable cookie
res.addHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
} @Override
public void destroy() {
// TODO Auto-generated method stub } }

上面提到了非简单请求,那什么是非简单请求呢,可以看下面的图:

非简单请求会发出一个预检命令的(当然了,我们上面的Filter已经解决预检命令的问题了):

Spring框架解决

如果使用的是Spring框架的话,那就只需要一个注解就能够解决跨域的问题了@CrossOrigin

HTTP服务器层

我们在的商用开发中,一般请求的过程是这样的:浏览器->HTTP服务器(Nginx,Apache)->应用服务器(Tomcat,Weblogic)

上面编写的Filter、Spring框架都是在应用服务器上解决的,我们也是可以通过HTTP服务器(Nginx,Apache)来进行解决跨域问题的

Nginx我用过,Apache我倒是还没用过,下面就简单记录了Nginx和Apache是如何配置的:

Nginx配置:

Apache配置:

代理解决跨域问题

在之前的图我们已经看到了,解决跨域的问题可以在“调用方”中来进行解决。

“调用方”解决跨域的问题是这个思路的:让发送出去的请求代理成是本域的

举个例子:

www.zhongfucheng.top是调用方

www.zhongfucheng.site是被调用方

它俩是不同域的,但我们可以在nginx或Apache上进行配置代理:将被调用方www.zhongfucheng.site映射成别的路径

比如,像下面的图,将8080端口的映射成了ajaxServer,当调用方访问ajaxServer路径时,这样的方法在外部看起来就不像是跨域了,像是访问本地(8081端口),但实际访问别的域(8080端口)

总结

令我感到最简单的是通过Spring的注解就可以解决跨域的问题了,JSONP的方式已经是很少用的了,因为存在一定的弊端,但了解一下也无妨,毕竟可能面试的时候会问到。当没有用任何框架的时候,写Filter也不麻烦,也只是配置了一下HTTP头信息而已。如果使用Nginx、Apache时,也可以用代理或者配置HTTP头信息都可以解决。看完之后,有没有觉得跨域问题就迎刃而解了。


如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y

AJAX跨域完全讲解的更多相关文章

  1. ajax跨域原理以及解决方案

    说明 跨域主要是由于浏览器的“同源策略”引起,分为多种类型,本文主要探讨Ajax请求跨域问题 前言 强烈推荐阅读参考来源中的文章,能够快速帮助了解跨域的原理 参考来源 本文参考了以下来源 浏览器同源政 ...

  2. AJAX跨域调用相关知识-CORS和JSONP(引)

    AJAX跨域调用相关知识-CORS和JSONP 1.什么是跨域 跨域问题产生的原因,是由于浏览器的安全机制,JS只能访问与所在页面同一个域(相同协议.域名.端口)的内容. 但是我们项目开发过程中,经常 ...

  3. ajax跨域相关

    ajax 技术使用xmlhttprequest组件附送请求时,发送请求的url和本网页的url地址必须在同一个域名下如果需要跨域,可以使用iframe或者<javascript src=&quo ...

  4. ajax跨域请求学习笔记

    原文:ajax跨域请求学习笔记 前言 ajax,用苍白的话赞扬:很好. 我们可以使用ajax实现异步获取数据,减少服务器运算时间,大大地改善用户体验:我们可以使用ajax实现小系统组合大系统:我们还可 ...

  5. Javascript&Ajax-深入浅出JSONP--解决ajax跨域问题

    Javascript&Ajax-深入浅出JSONP--解决ajax跨域问题 原理讲解: 链接地址:http://www.cnblogs.com/chopper/archive/2012/03/ ...

  6. Ajax 跨域难题 - 原生 JS 和 jQuery 的实现对比

    讲解顺序: AJAX 的概念及由来 JS 和 jQuery 中的 ajax 浏览器机制 AJAX 跨域 AJAX 的概念 在讲解 AJAX 的概念之前,我先提一个问题. 这是一个典型的 B/S 模式. ...

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

    Ajax跨域问题及解决方案   目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...

  8. e3mall商城总结11之sso系统的分析、应用以及解决ajax跨域问题

    说在前面的话 一.sso系统分析 什么是sso系统 SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次 ...

  9. Laravel中的ajax跨域请求

    最近接触Laravel框架ajax跨域请求的过程中遇到一些问题,在这里做下总结. 一开始发起ajax请求一直报500错误,搜索相关资料后发现Laravel要允许跨域请求可以加入Cors中间件,代码如下 ...

随机推荐

  1. Servlet--取得session,application内置对象

    在前面的博客里面,使用Servlet取得了request,response,config对象,实际上通过Servlet程序也可以取得session,application等内置对象. 1,通过Http ...

  2. 【Python3之迭代器,生成器】

    一.可迭代对象和迭代器 1.迭代的概念 上一次输出的结果为下一次输入的初始值,重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值 注:循环不是迭代 while True: ...

  3. promise使用方法

    代码报错会走向失败时的回调 let p = new Promise((resolve, reject) => { throw new Error("我错了"); //会失败 ...

  4. 【转】C++易混知识点5:实例讲解Public Protected Private作用域,继承的区别和用意

    大学生涯,涉及到类的作用域,继承都是用的public 共有继承,当时也没想那么多,觉得共有继承多方便,多简单,反正没有太多的限制,不管是类的成员或者是基类的成员函数都可以访问.没有深究.其实这里面真是 ...

  5. redis数据类型-列表类型

    列表类型 列表类型(list)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段. 列表类型内部是使用双向链表(double linked list)实现的,所以向 ...

  6. Docker之镜像

    镜像(Images) 镜像是Docker的三大核心之一,类似于虚拟机,作用和虚拟机是一样的,唯独是组成部分会有些区别.简单的说如果我们想启动一个容器就必须要有镜像.docker运行容器前需要本地存在对 ...

  7. Technical debt

    What is Technial debt? Technical debt is not bug. It is that the feature can work, but it is not a p ...

  8. MySQL数据库中实现对中文字段按照首字字母排序

    转载自网络! 1. 在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的. 这种情况在MySQL的很多版本中都存在. 如果这个问题不解决, ...

  9. 轮询、长轮询、长连接、flash socket 的区别

    轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 优点:后端程序编写比较容易. 缺点:请求中有大半是无用,浪费带宽和服务器资源. 实例:适于小型应用. 长轮询:客 ...

  10. C# 实现Html转JSON

    Html为树结构->Json为数组结构 应用场景 H5或浏览器展示Html代码没有问题,但是让原生APP或ReactNative直接展示Html可能会有很多不便 实现方法 可以通过正则表达式捕获 ...