Ajax 跨域请求详解
来源:互联网 发布:touchslide.js 编辑:程序博客网 时间:2024/06/02 04:37
问题描述:
实际开发中,我们经常会看到这样的错误提示:
XMLHttpRequest cannot load http://…… No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘null’ is therefore not allowed access.
其实这就是ajax跨域请求失败的错误。这里小编整理几种解决方案供大家一起学习。
出现跨域请求错误的原因:
域英文叫DOMAIN——域(Domain)是Windows网络中独立运行的单位,域之间相互访问则需要建立信任关系(即Trust Relation)。信任关系是连接在域与域之间的桥梁。当一个域与其他域建立了信任关系后,2个域之间不但可以按需要相互进行管理,还可以跨网分配文件和打印机等设备资源,使不同的域之间实现网络资源的共享与管理,以及相互通信和数据传输。
域既是 Windows 网络操作系统的逻辑组织单元,也是Internet的逻辑组织单元,在 Windows 网络操作系统中,域是安全边界。域管理员只能管理域的内部,除非其他的域显式地赋予他管理权限,他才能够访问或者管理其他的域,每个域都有自己的安全策略,以及它与其他域的安全信任关系。
说到这里就不得不说同源策略:同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。eg:当一个浏览器的两个tab页中分别打开百度和谷歌的页面时,百度页执行脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。
解决方案:
1. 通过 jsonp 解决请求跨域问题
2. 通过 ServletRequest 中 setHeader 方法解决函数请求跨域问题
具体实例:
首先,我们先写出一般情况下的 ajax 请求效果。
案例结构
html代码
<html><head> <meta charset="UTF-8"> <title>Demo</title> <script type="text/javascript" src="jquery-1.12.4.min.js"></script> <script type="text/javascript"> $(function () { $.ajax({ type : "get", async:false, url : "http://localhost:8080/Ajax/Service", success : function(data){ $(".showcontent").text("name:"+data.name+" | sex:"+data.sex); }, error:function(){ alert('fail'); } }) }) </script></head><body> <div class="showcontent" style="margin: auto;border: 1px solid red;width:300px;height:250px;padding:30px;"></div></body></html>
java代码
package com.idol.controller;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Service extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setContentType("application/json;charset=UTF-8"); //定义响应类型,防止ie下载json文件 String json = "{\"name\":\"idol\",\"sex\":\"male\"}"; //当自定义 json 对象时需要注意:除 boolean 和 int 类型的值外,其他参数类型必须均为字符串类型,故需用 \" 符号包裹。 PrintWriter out = resp.getWriter(); try { out.print(json); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } } }
web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Ajax</display-name> <servlet> <servlet-name>Service</servlet-name> <servlet-class>com.idol.controller.Service</servlet-class> </servlet> <servlet-mapping> <servlet-name>Service</servlet-name> <url-pattern>/Service</url-pattern> </servlet-mapping></web-app>
页面显示如下内容:
name:idol | sex:male
通常情况下我们通过请求拿到的 json 数据是这样的:
{"name":"idol","sex":"male"}
而 jsonp 格式的数据是这样的:
callback({"name":"idol","sex":"male"})
类似于被一个回调函数包裹着一样。
A . jsonp 解决方案:
首先,通过 jsonp 去处理 ajax 请求跨域问题的时候,无论是通过 jQuery 还是原生的 JS 我们都需要对 java 代码中的 PrintWriter 输出的参数进行设置。它的参数不再是以前的 json 格式的数据,取而代之的是一个回调函数。
I . 使用 javascript 完成跨域请求
java代码
package com.idol.controller;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Service extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setContentType("application/json;charset=UTF-8");//定义响应类型,防止ie下载json文件 String json = "{\"name\":\"idol\",\"sex\":\"male\"}"; /*当自定义 json 对象时需要注意:除 boolean 和 int 类型的值外, 其他参数类型必须均为字符串类型,故需用 \" 符号包裹。*/ String back = req.getParameter("callback"); /*注意,以此 URL 为例: http://localhost:8081/Ajax/Service?back=callback 在原生 js 中,getParameter() 的参数必须与等号前的参数相同, 等号后的参数必须与 js 中定义的 callback 函数同名; */ PrintWriter out = resp.getWriter(); try { out.print(back+"("+json+")"); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } } }
html代码
<html><head> <meta charset="UTF-8"> <title>Demo</title> <script type="text/javascript" src="jquery-1.12.4.min.js"></script> </head><body> <pre class="showcontent"></pre> <script type="text/javascript"> function callback (data) { $(".showcontent").text("name:"+data.name+" | sex:"+data.sex) } </script> <script type="text/javascript" src="http://localhost:8081/Ajax/Service?back=callback"></script></body></html>
PS:
1. 此时的 html 文件是在桌面新建的,并没有与 servlet 在同一项目中
-
<script type="text/javascript" src="http://localhost:8081/Ajax/Service?back=callback">
jsonp 的引入必须在 <script type="text/javascript">……</script>
下。
- <script type="text/javascript">……</script>
中 callback 函数不可包裹在其他函数内,包括window.onload=function () {}
函数中。
II . 使用 JQuery 完成跨域请求
java 代码同 JavaScript 部分
html 代码
<html><head> <meta charset="UTF-8"> <title>Demo</title> <script type="text/javascript" src="jquery-1.12.4.min.js"></script> <script type="text/javascript"> $(function () { $.ajax({ type : "get", async:false, url : "http://localhost:8081/Ajax/Service", dataType : "jsonp",//数据类型为jsonp jsonp: "callback",//服务端用于接收callback调用的function名的参数 success : function(data){ $(".showcontent").text("name:"+data.name+" | sex:"+data.sex); }, error:function(){ alert('fail'); } }); }) </script></head><body> <div class="showcontent"></div></body></html>
当然 jQuery 中除了 ajax 函数还可以通过 getJSON 函数进行请求。具体代码如下:
<html><head> <meta charset="UTF-8"> <title>Demo</title> <script type="text/javascript" src="jquery-1.12.4.min.js"></script> <script type="text/javascript"> $(function () { $.getJSON("http://localhost:8081/Ajax/Service?callback=?",function(data){ $(".showcontent").text("name:"+data.name+" | sex:"+data.sex); }); }) </script></head><body> <div class="showcontent"></div></body></html>
B . java servlet 中的解决方案:
I . 在 servlet 中改
java 代码
package com.idol.controller;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Service extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setHeader("Access-Control-Allow-Origin", "*"); //设置可以访问的 URL resp.setHeader("Access-Control-Allow-Methods","GET,POST"); //设置访问的方式 resp.setContentType("text/html;charset=UTF-8"); //定义响应类型,防止ie下载json文件 String json = "{\"name\":\"idol\",\"sex\":\"male\"}"; //当自定义 json 对象时需要注意:除 boolean 和 int 类型的值外,其他参数类型必须均为字符串类型,故需用 \" 符号包裹。 PrintWriter out = resp.getWriter(); try { out.print(json); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } } }
html 代码
<html><head> <meta charset="UTF-8"> <title>Demo</title> <script type="text/javascript" src="jquery-1.12.4.min.js"></script> <script type="text/javascript"> $(function () { $.ajax({ type : "get", async:false, url : "http://localhost:8081/Ajax/Service", success : function(data){ var json = eval("("+data+")"); $(".showcontent").text("name:"+json.name+" | sex:"+json.sex); }, error:function(){ alert('fail'); } }); }) </script></head><body> <div class="showcontent"></div></body></html>
II . 设置过滤器
Java代码
package com.ev_image.servlet;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.HttpServletResponse;public class CorsFilter implements Filter { @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub HttpServletResponse resp = (HttpServletResponse) response; resp.setContentType("text/html;charset=UTF-8"); resp.setHeader("Access-Control-Allow-Origin", "*"); resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); resp.setHeader("Access-Control-Max-Age", "0"); resp.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token"); resp.setHeader("Access-Control-Allow-Credentials", "true"); resp.setHeader("XDomainRequestAllowed","1"); chain.doFilter(request, response); } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub }}
web.xml
<filter> <filter-name>corsfilter</filter-name> <filter-class>com.ev_image.servlet.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>corsfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
html 代码同上。
- Ajax 跨域请求详解
- ajax请求跨域请求
- AJAX(XMLHttpRequest)进行跨域请求方法详解
- AJAX(XMLHttpRequest)进行跨域请求方法详解
- AJAX(XMLHttpRequest)进行跨域请求方法详解
- AJAX(XMLHttpRequest)进行跨域请求方法详解
- AJAX(XMLHttpRequest)进行跨域请求方法详解
- solr+ajax智能拼音详解---solr跨域请求
- AJAX(XMLHttpRequest)进行跨域请求方法详解(一)
- AJAX(XMLHttpRequest)进行跨域请求方法详解
- AJAX(XMLHttpRequest)进行跨域请求方法详解
- ajax 跨域请求
- AJAX跨域请求
- Ajax跨域请求
- ajax跨域请求
- ajax跨域请求
- Ajax跨域请求
- ajax 跨域请求
- 第四周:[Leetcode]207. Course Schedule
- 浅谈各种拒绝服务攻击的原理与防御
- 支持对列表操作的栈(lua)
- 学习记录
- 验证码倒计时JS
- Ajax 跨域请求详解
- DbUtils(二) 结果集实例
- Springboot启动源码详解
- 迷宫寻宝(一)
- [U3D][Editor]编辑材质球遇到的一些问题
- 四则(栈or二叉树)
- css3:-webkit-box
- OC学习记录2:数组
- 算法分析与设计第四周:513. Find Bottom Left Tree Value