异步通信技术AJAX | AJAX实现省市联动、AJAX跨域问题
目录
一:异步通信技术AJAX | 快速搞定AJAX(第四篇)
1、AJAX实现省市联动
2、超链接、form表单和JS代码跨域
3、AJAX跨域问题
(1)测试Ajax跨域访问
(2)同源 & 不同源
(3)AJAX跨域解决方案1:设置响应头
(4)AJAX跨域解决方案2:jsonp
(5)AJAX跨域解决方案3:jQuery封装的jsonp
(6)AJAX跨域解决方案4:代理机制(httpclient)
(7)AJAX跨域解决方案5:nginx反向代理
一:异步通信技术AJAX | 快速搞定AJAX(第四篇)
1、AJAX实现省市联动
(1)什么是省市联动? -
在网页上,选择对应的省份之后,动态的关联出该省份对应的市。选择对应的市之后,动态的关联出该市对应的区。(首先要清楚需求)
(2)进行数据库表的设计:t_area (区域表)
将全国所有的省、市、区、县等信息都存储到一张表当中。
采用的存储方式实际上是code(编号) 和 pcode(父编号)形势。
id(PK-自增) code(编号) name(名字) pcode(父编号)
(3)建表t_area,模拟好数据;这里只做省市!
(4)页面加载完毕之后,先把省份全部展现出来
注:这里还是要先创建一个Area类,把从数据库中取出来的数据放里面,然后在放入一个List集合,最终 响应给浏览器,进行处理
Area类
package com.bjpowernode.javaweb.bean;/** * @program: 代码 * @ClassName: Area * @version: 1.0 * @description: 区域 * @author: bjpowernode * @create: 2022-05-15 22:02 **/public class Area { private String code; private String name; public Area() { } public Area(String code, String name) { this.code = code; this.name = name; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
前端代码
省市联动 $(function () { // 页面加载 $.ajax({ //传一个JSON格式的数据过去 type : "get", url : "/ajax/listArea", data : "t=" + new Date().getTime(), async : true, success : function (jsonArr) { // 拿到数据进行拼串,然后放到下拉列表select下面 var html = "--请选择省份--"; // 拿到的JSON数据肯定是一个数组 for (var i = 0; i <jsonArr.length; i++) { var area = jsonArr[i]; html += ""+area.name+"" } // 拼好串以后,把数据放到下拉列表中输出 $("#province").html(html) } }) })
后端代码
package com.bjpowernode.javaweb.ajax;import com.alibaba.fastjson.JSON;import com.bjpowernode.javaweb.bean.Area;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.sql.*;import java.util.*;/** * @program: 代码 * @ClassName: ListAreaServlet * @version: 1.0 * @description: 动态获取对应的区域 * @create: 2022-05-15 21:57 **/@WebServlet("/listArea")public class ListAreaServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 连接数据库,获取所有的对应区域。最终响应一个JSON格式的字符串给WEB前端。 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List areaList = new ArrayList(); try { // 注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 获取连接 String url = "jdbc:mysql://localhost:3306/bjpowernode?useUnicode=true&characterEncoding=UTF-8"; String user = "root"; String password = "123"; conn = DriverManager.getConnection(url, user, password); System.out.println(conn); // 获取预编译数据库操作对象 String sql = "select code,name from t_area where pcode is null"; ps = conn.prepareStatement(sql); // 执行SQL rs = ps.executeQuery(); // 处理结果集 while (rs.next()) { // 取出数据 String code = rs.getString("code"); String name = rs.getString("name"); // 封装一个类,把数据放入里面 Area a = new Area(code, name); // 把这个类再放到集合里面 areaList.add(a); } } catch (Exception e) { e.printStackTrace(); } finally { // 释放资源 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } response.setContentType("text/html;charset=UTF-8"); // 使用fastjson将java对象转换成json字符串。 String json = JSON.toJSONString(areaList); // 响应JSON。 response.getWriter().print(json); }}
效果展示:只要类一加载就会从数据中获取省份
(5)然后选择省份,只要change事件一发生,就发送Ajax请求,显示出对应的市
前端代码
change时间发生,发送Ajax请求,然后根据pcode获取对应的市;在定义一个下拉列表,进行数据的显示
省市联动 $(function () { // 页面加载 $.ajax({ //传一个JSON格式的数据过去 type : "get", url : "/ajax/listArea", data : "t=" + new Date().getTime(), async : true, success : function (jsonArr) { // 拿到数据进行拼串,然后放到下拉列表select下面 var html = "--请选择省份--"; // 拿到的JSON数据肯定是一个数组 for (var i = 0; i <jsonArr.length; i++) { var area = jsonArr[i]; html += ""+area.name+"" } // 拼好串以后,把数据放到下拉列表中输出 // 这是省的下拉列表 $("#province").html(html) } }) // 只要province元素的change事件发生,就发送请求 $("#province").change(function(){ // 发送ajax请求 $.ajax({ type : "get", url : "/ajax/listArea", // 这里要把pcode传过去,this.value就是获取到的pcode data : "t=" + new Date().getTime() + "&pcode=" + this.value, async : true, success : function(jsonArr){ var html = "--请选择市--"; for (var i = 0; i < jsonArr.length; i++) {var area = jsonArr[i]html += ""+area.name+"" } // 这是市的下拉列表 $("#city").html(html) } }) }) })
后端代码
两个Ajax请求可以共享一个Servlet;主要就是先获取pcode,看pcode是不是null:
如果是null表示发送的是页面加载显示省的请求;
如果不是null表示发送的是change时间显示市的请求
package com.bjpowernode.javaweb.ajax;import com.alibaba.fastjson.JSON;import com.bjpowernode.javaweb.bean.Area;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.sql.*;import java.util.*;/** * @program: 代码 * @ClassName: ListAreaServlet * @version: 1.0 * @description: 动态获取对应的区域 * @create: 2022-05-15 21:57 **/@WebServlet("/listArea")public class ListAreaServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取到前端发送的pcode String pcode = request.getParameter("pcode"); // 连接数据库,获取所有的对应区域。最终响应一个JSON格式的字符串给WEB前端。 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List areaList = new ArrayList(); try { // 注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 获取连接 String url = "jdbc:mysql://localhost:3306/bjpowernode?useUnicode=true&characterEncoding=UTF-8"; String user = "root"; String password = "123"; conn = DriverManager.getConnection(url, user, password); // 获取预编译数据库操作对象 String sql = ""; if (pcode == null){// 如果pcode为null表示是省 sql = "select code,name from t_area where pcode is null"; ps = conn.prepareStatement(sql); }else {// 如果pcode不为null表示是市 sql = "select code,name from t_area where pcode = ?"; ps = conn.prepareStatement(sql); ps.setString(1,pcode); } // 执行SQL rs = ps.executeQuery(); // 处理结果集 while (rs.next()) { // 取出数据 String code = rs.getString("code"); String name = rs.getString("name"); // 封装一个类,把数据放入里面 Area a = new Area(code, name); // 把这个类再放到集合里面 areaList.add(a); } } catch (Exception e) { e.printStackTrace(); } finally { // 释放资源 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } response.setContentType("text/html;charset=UTF-8"); // 使用fastjson将java对象转换成json字符串。 String json = JSON.toJSONString(areaList); // 响应JSON。 response.getWriter().print(json); }}
执行效果:
①选择省:发送页面加载的Ajax请求
②省选择以后,发生了change事件,机会发送显示对应市的Ajax请求
2、超链接、form表单和JS代码跨域
(1)跨域是指从一个域名的网页去请求另一个域名的资源。比如从百度(https://baidu.com)页面去请求京东(https://www.jd.com)的资源。
(2)通过超链接、form表单提交或者JS代码的window.location.href的方式进行跨域是不存在问题的!但在一个域名的网页中的一段js代码发送ajax请求去访问另一个域名中的资源,由于同源策略的存在导致无法跨域访问,那么ajax就存在这种跨域问题。
(3)同源策略是指一段脚本只能读取来自同一来源的窗口和文档的属性,同源就是协议、域名和端口都相同。
(4)同源策略有什么用?如果你刚刚在网银输入账号密码,查看了自己还有1万块钱,紧接着访问一些不规矩的网站,这个网站可以访问刚刚的网银站点,并且获取账号密码,那后果可想而知。所以,从安全的角度来讲,同源策略是有利于保护网站信息的。
(5)有一些情况下,我们是需要使用ajax进行跨域访问的。比如某公司的A页面(a.bjpowernode.com)有可能需要获取B页面(b.bjpowernode.com)。
(6)测试
①对于超链接、form表单、JS代码;都是改变了地址栏的地址,是可以跨域访问的
②对于Ajax,并没有改变地址栏的地址,是不能跨域访问的
模拟超链接、form表单、JS代码方式跨域问题
步骤一:创建两个模块a和b,整两个Tomcat服务器
步骤二:默认a的HTTP端口号是8080,JMX端口号是1099;修改b的HTTP端口号为8081,JMX端口号是1098;不然在同一台服务器上端口号会冲突
步骤三:
①对于超链接,写两个index.html页面,就从a的index.html页面跨域访问b的index.html页面
②对于form表单的形式,a通过提交forrm表单发送数据,b接收请求在Servlet中获取数据
③对于JS代码,直接定义个按钮,通过点击事件onclick进行跳转到b的index.html
④通过标签加载b站点的web根目录下的my.js文件
⑤使用img标签加载b站点的web目录下的baidu.png图片
😊对于a站点代码
index.html
a应用的index页面 b的index页面(跨域) 用户名:
密码:

😊对于b站点代码
index.html
b应用的index页面 b应用的index页面
请求Servlet
package com.bjpowernode.zl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/user/reg")public class UserRegServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取用户名和密码 String username = request.getParameter("username"); String password = request.getParameter("password"); // 响应到前端 response.getWriter().print(username + ":" + password); }}
web跟下的my.js文件和baidu.png图片
😊测试结果:以上请求都是支持跨域的,资源都能跨域访问到
3、AJAX跨域问题
(1)测试Ajax跨域访问
①默认情况下:发送ajax跨域请求的时候会出现以下错误:Access to XMLHttpRequest at 'http://localhost:8081/b/hello' from origin 'http://localhost:8080' has been blocked by CORS policy:No 'Access-Control-Allow-Origin' header is present on the requested resource.
②出现这个错误的根本原因是:跨域的时候,不允许共享同一个XMLHttpRequest对象,因为共享同一个XMLHttpRequest对象是不安全的。
③重点提示:CORS策略阻止(这个ajax跨域请求被同源策略阻止)。
④什么是同源策略?同源策略是浏览器的一种安全策略。
a站点发送Ajax请求
测试:ajax跨域访问会不会有问题 window.onload = function(){ document.getElementById("btn").onclick = function(){ // 发送ajax的跨域请求 // 1. 创建核心对象 var xmlHttpRequest = new XMLHttpRequest(); // 2. 注册回调函数 xmlHttpRequest.onreadystatechange = function(){ if (xmlHttpRequest.readyState == 4) { if (xmlHttpRequest.status >= 200 && xmlHttpRequest.status < 300) { document.getElementById("mydiv").innerHTML = xmlHttpRequest.responseText } } } // 3. 开启通道 xmlHttpRequest.open("GET", "http://localhost:8081/b/hello", true) // 4. 发送请求 xmlHttpRequest.send() } }
b站点进行响应
package com.bjpowernode.zl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/hello")public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 响应 response.getWriter().print("hello ajax!!!"); }}
效果展示:Ajax请求时不支持跨域问题的
(2)同源 & 不同源
①区分同源和不同源的三要素:协议、域名、端口
②协议一致,域名一致,端口号一致,三个要素都一致,才是同源,其它一律都是不同源
③同源:XMLHttpRequest对象可以共享;不同源:XMLHttpRequest对象不可以共享。
④判别同不同源的例子:
URL1 | URL2 | 是否同源 | 描述 |
---|---|---|---|
http://localhost:8080/a/index.html | http://localhost:8080/a/first | 同源 | 协议 域名 端口一致 |
http://localhost:8080/a/index.html | http://localhost:8080/b/first | 同源 | 协议 域名 端口一致 |
http://www.myweb.com:8080/a.js | https://www.myweb.com:8080/b.js | 不同源 | 协议不同 |
http://www.myweb.com:8080/a.js | http://www.myweb.com:8081/b.js | 不同源 | 端口不同 |
http://www.myweb.com/a.js | MyWeb2.com is for sale | HugeDomains | 不同源 | 域名不同 |
http://www.myweb.com/a.js | http://crm.myweb.com/b.js | 不同源 | 子域名不同 |
(3)AJAX跨域解决方案1:设置响应头
①核心原理:跨域访问的资源允许你跨域访问。
②b站点的Servlet设置响应头,就表示允许你跨域访问。
③http://localhost:8080表示允许http协议、域名为localhost、端口号为8080的服务器跨域访问;*就表示允许所有的服务器进行跨域访问。
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");response.setHeader("Access-Control-Allow-Origin", "*");
b站点响应代码加上设置响应头
package com.bjpowernode.zl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/hello")public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应头,允许ajax跨域请求 response.setHeader("Access-Control-Allow-Origin","http://localhost:8080"); // 响应 response.getWriter().print("hello ajax!!!"); }}
效果展示:Ajax请求时跨域可以正常访问
(4)AJAX跨域解决方案2:jsonp
①jsonp:json with padding(带填充的json)
②jsonp不是一个真正的ajax请求,只不过可以完成ajax的局部刷新效果。可以说jsonp是一种类似ajax请求的机制!
③jsonp不是ajax请求,但是可以完成局部刷新的效果,并且可以解决跨域问题。
④注意:jsonp解决跨域的时候,只支持GET请求,不支持post请求!
⑤使用script标签,通过src属性发出请求,进行跨域访问!
😊jsop初步:其实Ajax没什么关系,发送Ajax请求是需要使用XMLHttpRequest对象的
a站点发送请求
jsonp实现跨域 /*function sayHello() { alert("Hello World"); }*/ function sayHello(data) { alert("username="+data.name) }
b站点进行响应
package com.bjpowernode.zl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;/** * @Author:朗朗乾坤 * @Package:com.bjpowernode.zl * @Project:ajax * @name:JsonpServlet1 * @Date:2022/12/12 15:27 */@WebServlet("/jsonp1")public class JsonpServlet1 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); // 1、在后台进行输出一个普通的字符串 System.out.println("jsonp方式完成跨域访问"); // 2、向前端响应一段JS代码 PrintWriter out = response.getWriter(); // 这是响应一段js代码,只不过这个alert函数是JS内置的函数,可以直接用 out.print("alert(123)"); // 这行代码就相当于写到a站点.html的script标签里 // 3、调用函数 // 这也是响应一段JS代码,只不过这个sayHello函数是程序员自定义的 // 后端把sayHello()字符串响应到浏览器上,浏览器去调用这个函数 out.print("sayHello()"); // 4、函数中响应一个JSON数据 out.print("sayHello({\"name\" : \"jackson\"})"); // 5、动态获取函数名 String fun = request.getParameter("fun"); out.print(fun+"({\"name\" : \"jackson\"})"); }}
😊jsonp深入:初步中页面一打开就加载script标签,并没有达到页面局部刷新的效果;我们要做的是先加载完,然后点击按钮才会加载script标签;实际上就是script标签中套script标签
a站点发送请求
script标签中套script标签四步:
①创建script元素对象:document.createElement("script");②设置script的type属性:script元素对象.type = "text/javascript"
③设置script的src属性:script元素对象.src = "http://localhost:8081/b/jsonp2?fun=sayHello"
④加载script,将script对象添加到body标签中:document.getElementsByTagName("body")[0].appendChild(htmlScriptElement)
jsonp跨域深入 // 自己定义的函数 function sayHello(data) { document.getElementById("mydiv").innerHTML = data.username } // 点击按钮加载script标签 window.onload = function () { document.getElementById("btn").onclick = function () { // 加载script元素 //1.创建script元素对象 var htmlScriptElement = document.createElement("script"); //2.设置script的type属性 htmlScriptElement.type = "text/javascript" //3.设置script的src属性 htmlScriptElement.src = "http://localhost:8081/b/jsonp2?fun=sayHello" // 将script对象添加到body标签中(这一步就是加载script) document.getElementsByTagName("body")[0].appendChild(htmlScriptElement) } }
b站点进行响应
package com.bjpowernode.zl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/jsonp2")public class JSONPServlet2 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取函数名 String fun = request.getParameter("fun"); // 响应一段js代码 response.getWriter().print(fun + "({\"username\" : \"lucy\"})"); }}
(5)AJAX跨域解决方案3:jQuery封装的jsonp
①大牛们写的jQuery库,已经对jsonp进行了封装,可以直接拿来用。
②用之前需要引入jQuery库的js文件。
③jQuery中的jsonp其实就是我们上面代码的高度封装,底层原理完全相同。
④核心代码
$.ajax({ type : "GET", url : "跨域的url", dataType : "jsonp", // 指定数据类型 jsonp : "fun", // 指定参数名(不设置的时候,默认是:"callback") jsonpCallback : "sayHello" // 指定回调函数的名字 // (不设置的时候,jQuery会自动生成一个随机的回调函数,//并且这个回调函数还会自动调用success的回调函数。)})
步骤一:先创建一个目录,然后把官方的jQuery放进去
步骤二:
前端代码
第一种方式:全都采用默认的方式
虽然url : "http://localhost:8081/b/jsonp3"这样传,但是实际上会自动转换为以下代码
http://localhost:8081/b/jsonp3?callback=jQuery36006725923678901025_1670837696149&_=1670837696150
①callback=jQuery36006725923678901025_1670837696149,callback就是name相当于之前的fun;
②jQuery36006725923678901025_1670837696149就是函数名,相当于之前的sayHello,而这个名字是jQuery自动为我们生成的;
③&_=1655528968613是一个时间戳。
④并且自动生成的这个函数,默认情况还会自动调用我们传的success回调函数
⑤最关键的是传参的时候要指定数据类型是jsonp形式,dataType : "jsonp"
jQuery的jsonp封装解决ajax跨域问题 $(function () { $("#btn").click(function () { // 发送所谓的ajax请求,实际上并不是 $.ajax({ // 传一个JSON数据过去 type : "GET", // jsonp请求只支持get请求。 url : "http://localhost:8081/b/jsonp3", dataType : "jsonp", // 指定数据类型是jsonp形式。【跨域最关键的是它】 success : function (data) { // data是一个json:{"username":"lisi"}) $("#mydiv").html(("欢迎你:" + data.username)) } }) }) })
第二种方式:采用自定义的方式
①使用jsonp属性,用来指定参数的名字
②使用jsonpCallback属性,用这个属性来指定具体的回调函数
jQuery的jsonp封装解决ajax跨域问题 // 自定义函数 function sayHello(data) { $("#mydiv").html(("欢迎你:" + data.username)) } $(function () { $("#btn").click(function () { // 发送所谓的ajax请求,实际上并不是 $.ajax({ // 传一个JSON数据过去 type : "GET", // jsonp请求只支持get请求。 url : "http://localhost:8081/b/jsonp3", dataType : "jsonp", // 指定数据类型是jsonp形式。【跨域最关键的是它】jsonp : "fun", /*第一种方式 jsonpCallback : function (data) { $("#mydiv").html(("欢迎你:" + data.username)) }*/ // 第二种方式 jsonpCallback : "sayHello" }) }) })
后端代码
①采用默认的方式,name就是callback,通过name获取对应的函数名
②采用自定义的方式,通过前端定义的jsonp属性指定的名字获取函数名
package com.bjpowernode.zl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/jsonp3")public class JSONPServlet3 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取函数名,callback名称是默认的 String callback = request.getParameter("callback"); // 响应一段js代码,调用函数 response.getWriter().print(callback + "({\"username\":\"lisi\"})"); // 获取函数名,使用自定义的 String fun = request.getParameter("fun"); // 响应一段js代码,调用函数 response.getWriter().print(fun + "({\"username\":\"lisi\"})"); }}
(6)AJAX跨域解决方案4:代理机制(httpclient)
(1)代理机制:既然服务及不能直接跨域发送Ajax请求访问;那么先不跨域发送Ajax请求给Servlet,然后在通过这个Servlet(java代码)发送请求进行跨域访问!
(2)使用Java程序怎么去发送get/post请求呢?【GET和POST请求就是HTTP请求。】
①第一种方案:使用JDK内置的API(java.net.URL.....),这些API是可以发送HTTP请求的;但是编写代码很麻烦,不建议使用。
②第二种方案:使用第三方的开源组件,比如:apache的httpclient组件。(httpclient组件是开源免费的,可以直接用)
(3)在java程序中,使用httpclient组件可以发送http请求。
①对于httpclient组件的代码,目前可以不进行深入的研究,可以从网上直接搜;然后粘贴过来,改一改,看看能不能完成发送get和post请求。
②使用httpclient组件,需要将这个组件相关的jar包引入到项目当中。
a站点的前端代码
使用代理机制完成ajax跨域访问 // ES6当中的有一个新语法:箭头函数。 window.onload = function() { document.getElementById("btn").onclick = function() { // 发送ajax请求 // 1.创建核心对象 var xmlHttpRequest = new XMLHttpRequest(); // const可以声明变量。(可以自己研究一下:var let const声明变量时有什么区别) // 2.注册回调函数 xmlHttpRequest.onreadystatechange = function() { if (xmlHttpRequest.readyState == 4) { // 这里也可以使用区间的方式,因为状态码是200~299都是正常响应结束。 if (xmlHttpRequest.status >= 200 && xmlHttpRequest.status < 300) { document.getElementById("mydiv").innerHTML = xmlHttpRequest.responseText } } } // 3.开启通道 xmlHttpRequest.open("GET", "/a/proxy", true) // 4.发送请求 xmlHttpRequest.send() } }
a站点的Servlet代码,代理Servlet,先引入jar包手动Add,再在java代码中发送GET请求
package com.bjpowernode.zl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;@WebServlet("/proxy")public class ProxyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 通过httpclient组件,发送HTTP GET请求,访问 TargetServlet HttpGet httpGet = new HttpGet("http://localhost:8081/b/target"); httpGet.setHeader("Content-Type", "application/x-www-form-urlencoded"); CloseableHttpClient httpClient = HttpClients.createDefault(); HttpResponse resp = httpClient.execute(httpGet); HttpEntity entity = resp.getEntity(); BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); String line = null; StringBuffer responseSB = new StringBuffer(); while ((line = reader.readLine()) != null) { responseSB.append(line); } reader.close(); httpClient.close(); // b站点响应回来的数据 response.getWriter().print(responseSB); }}
b站点的Servlet,会返回一个json格式的字符串
package com.bjpowernode.zl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/target")public class TargetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 响应一个json字符串。 response.getWriter().print("{\"username\":\"jackson\"}"); }}
执行结果,也能完整跨域访问
(7)AJAX跨域解决方案5:nginx反向代理
nginx反向代理中也是使用了这种代理机制来完成AJAX的跨域,实现起来非常简单,只要修改一个nginx的配置即可。后面学习到互联网分布式技术会细讲!