异步通信技术AJAX | AJAX实现省市联动、AJAX跨域问题

news2024/10/5 3:18:50

目录

一:异步通信技术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;
    }
}

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>省市联动</title>
</head>
<body>
    <!--引入我们自己编写的jQuery库-->
    <script type="text/javascript" src="/ajax/js/jQuery-1.0.0.js"></script>
    <script type="text/javascript">
        $(function () { // 页面加载
            $.ajax({ //传一个JSON格式的数据过去
                type : "get",
                url : "/ajax/listArea",
                data : "t=" + new Date().getTime(),
                async : true,
                success : function (jsonArr) {
                    // 拿到数据进行拼串,然后放到下拉列表select下面
                    var html = "<option value=''>--请选择省份--</option>";
                    // 拿到的JSON数据肯定是一个数组
                    for (var i = 0; i <jsonArr.length; i++) {
                        var area = jsonArr[i];
                        html += "<option value='"+area.code+"'>"+area.name+"</option>"
                    }
                    // 拼好串以后,把数据放到下拉列表中输出
                    $("#province").html(html)
                }

            })
        })


    </script>

    <select id="province">
        <!--显示省份-->
    </select>
</body>
</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<Area> 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 = "***";
            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获取对应的市;在定义一个下拉列表,进行数据的显示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>省市联动</title>
</head>
<body>
    <!--引入我们自己编写的jQuery库-->
    <script type="text/javascript" src="/ajax/js/jQuery-1.0.0.js"></script>
    <script type="text/javascript">
        $(function () { // 页面加载
            $.ajax({ //传一个JSON格式的数据过去
                type : "get",
                url : "/ajax/listArea",
                data : "t=" + new Date().getTime(),
                async : true,
                success : function (jsonArr) {
                    // 拿到数据进行拼串,然后放到下拉列表select下面
                    var html = "<option value=''>--请选择省份--</option>";
                    // 拿到的JSON数据肯定是一个数组
                    for (var i = 0; i <jsonArr.length; i++) {
                        var area = jsonArr[i];
                        html += "<option value='"+area.code+"'>"+area.name+"</option>"
                    }
                    // 拼好串以后,把数据放到下拉列表中输出
                    // 这是省的下拉列表
                    $("#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 = "<option value=''>--请选择市--</option>";
                        for (var i = 0; i < jsonArr.length; i++) {
                            var area = jsonArr[i]
                            html += "<option value='"+area.code+"'>"+area.name+"</option>"
                        }
                        // 这是市的下拉列表
                        $("#city").html(html)
                    }
                })
            })

        })


    </script>

    <select id="province">
        <!--显示省份-->
    </select>

    <select id="city">
        <!--显示省份,上面change事件发生,这里就会显示数据-->
    </select>
</body>
</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<Area> 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 = "***";
            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

④通过<script>标签加载b站点的web根目录下的my.js文件

⑤使用img标签加载b站点的web目录下的baidu.png图片

😊对于a站点代码

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>a应用的index页面</title>
</head>
<body>
    <!--通过超连接的方式-->
    <a href="http://localhost:8081/b/index.html">b的index页面(跨域)</a>
    <!--使用form表单-->
    <form action="http://localhost:8081/b/user/reg" method="post">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        <input type="submit" value="注册">
    </form>
    <!--通过js代码中的window.location.href/document.location.href-->
    <button onclick="window.location.href='http://localhost:8081/b/index.html'">b的index页面(跨域访问)</button>
    <!--使用script标签加载js文件-->
    <script type="text/javascript" src="http://localhost:8081/b/my.js"></script>
    <!--加载b站点的图片-->
    <br>
    <img src="http://localhost:8081/b/baidu.png" />
</body>
</html>

😊对于b站点代码

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>b应用的index页面</title>
</head>
<body>
    <h1>b应用的index页面 </h1>
</body>
</html>

请求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请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试:ajax跨域访问会不会有问题</title>
</head>
<body>
<script type="text/javascript">

    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()
        }
    }

</script>
<button id="btn">发送ajax跨域请求</button>
<div id="mydiv"></div>
</body>
</html>

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对象不可以共享。

④判别同不同源的例子:

URL1URL2是否同源描述
http://localhost:8080/a/index.htmlhttp://localhost:8080/a/first同源协议 域名 端口一致
http://localhost:8080/a/index.htmlhttp://localhost:8080/b/first同源协议 域名 端口一致
http://www.myweb.com:8080/a.jshttps://www.myweb.com:8080/b.js不同源协议不同
http://www.myweb.com:8080/a.jshttp://www.myweb.com:8081/b.js不同源端口不同
http://www.myweb.com/a.jsMyWeb2.com is for sale | HugeDomains不同源域名不同
http://www.myweb.com/a.jshttp://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站点发送请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp实现跨域</title>
</head>
<body>
    <!--定义一个函数-->
    <script type="text/javascript">
        /*function sayHello() {
            alert("Hello World");
        }*/

        function sayHello(data) {
            alert("username="+data.name)
        }
    </script>

    <!--超链接也可以跨域,但是超链接点击之后会跳转页面,无法做到页面局部刷新效果
        script标签只是跨域去调用资源,并不会修改地址跳转页面-->
    <script type="text/javascript" src="http://localhost:8081/b/jsonp1?fun=sayHello">

    </script>


</body>
</html>

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)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp跨域深入</title>
</head>
<body>
    <script type="text/javascript">
        // 自己定义的函数
        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)
            }
        }
    </script>

    <button id="btn">jsonp解决跨域问题,达到ajax局部刷新的效果</button>
    <div id="mydiv"></div>
</body>
</html>

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"

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jQuery的jsonp封装解决ajax跨域问题</title>
</head>
<body>
    <!--引入jQuery库-->
    <script type="text/javascript" src="/a/js/jquery-3.6.0.min.js"></script>
    <script type="text/javascript">
      
        $(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))
                    }
                })
            })
        })
    </script>

    <button id="btn">jQuery库封装的jsonp</button>
    <div id="mydiv"></div>
</body>
</html>

 第二种方式:采用自定义的方式

①使用jsonp属性,用来指定参数的名字

②使用jsonpCallback属性,用这个属性来指定具体的回调函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jQuery的jsonp封装解决ajax跨域问题</title>
</head>
<body>
    <!--引入jQuery库-->
    <script type="text/javascript" src="/a/js/jquery-3.6.0.min.js"></script>
    <script type="text/javascript">

        // 自定义函数
        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"

                })
            })
        })
    </script>

    <button id="btn">jQuery库封装的jsonp</button>
    <div id="mydiv"></div>
</body>
</html>

 后端代码

①采用默认的方式,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站点的前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>使用代理机制完成ajax跨域访问</title>
</head>
<body>
<script type="text/javascript">
    // 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()
        }
    }
</script>
<button id="btn">使用代理机制解决ajax跨域访问</button>
<div id="mydiv"></div>
</body>
</html>

 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的配置即可。后面学习到互联网分布式技术会细讲!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/136510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

可以通过哪些方式了解量化接口level2?

可以通过哪些方式了解量化接口level2&#xff1f;大家可以去百查看关于量化交易接口的信息&#xff0c;根据小编对市场上大多数的level2接口了解发现既有要收费的也有免费的&#xff0c;一般来说第三方软件公司提供的都是收费的居多&#xff0c;一些正规券商提供的就是免费的居…

一文读懂自动驾驶汽车:软硬结合 造就未来出行体验(下篇)

在上篇&#xff0c;我们回顾了自动驾驶汽车的发展历史&#xff0c;介绍了自动驾驶汽车的工作原理。得益于 AI 技术的突破&#xff0c;自动驾驶汽车飞速发展&#xff0c;运算速度也从 2007 年的 230 FLOPS 跃升至 2022 年的 254 TOPS&#xff0c;向软件定义汽车发展。现在&#…

数据结构-考研难点代码突破 (C++实现有向无环图的拓扑排序)

文章目录1. AOE网2. 拓扑排序C代码1. AOE网 AOV网∶若用DAG 图&#xff08;有向无环图&#xff09;表示一个工程&#xff0c;其顶点表示活动&#xff0c;用有向边<Vi&#xff0c;Vj>表示活动 Vi必须先于活动Vj进行的这样一种关系&#xff0c;则将这种有向图称为顶点表示…

基于主从博弈的智能小区代理商定价策略及电动汽车充电管理(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

C语言贪吃蛇大作战

C语言贪吃蛇大作战 贪吃蛇大作战 1997 年&#xff0c;诺基亚公司发布了贪吃蛇游戏&#xff0c;并将其内置于诺基亚 6110 手机中&#xff0c;使这款游戏迅速风靡全球&#xff0c;成为一代经典。一般的观点认为&#xff0c;贪吃蛇是手机游戏的鼻祖。 与传统单人贪吃蛇不同的是&…

【时间之外】系统管人,能行?(冷眼旁观连载之一)

目录 写作初心 在用工具 某微 某道 某书 工具痛点 某微痛点 某道痛点 某书痛点 总结一下&#xff1a;功能复杂 2023年观察计划 最大痛点 效果跟踪 未完待续 写作初心 2022年应该是这一生中值得纪念的一年&#xff0c;疫情封控自不必说&#xff0c;对于个人而言&a…

traefik gateway api

背景 在使用istio后开始考虑网关了&#xff0c;istio已经有自己的网关&#xff0c;为什么还要另外找一个别的网关&#xff0c;参考了好几个文章大致结论是&#xff0c;istio的网关功能不够强大&#xff0c;下图红色的部分是istio网关暂时缺失的&#xff0c;所以我的结论是在is…

Monorepo 下 Git 工作流的最佳实践

作者&#xff1a;林宜丙 背景 没有哪一种 Git 工作流是银弹&#xff0c;合适的 Git 工作流往往取决于项目的代码规模、协作人数、应用场景等&#xff1b;本次分享先从适合小型 Monorepo 的 Feature branch 工作流开始分享&#xff0c;接着分享适用于中大型 Monorepo 的 Trunk…

头歌:Ping客户端创建原始套接字(底部附全关完整答案)

头歌实践教学平台 (educoder.net)为Ping客户端创建一个原始类型的套接字原始套接字套接字&#xff08;socket&#xff09;是一个抽象层网络应用程序可以通过它发送或接收数据&#xff0c;可对其进行像文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中&a…

<C++>二叉树进阶

文章目录为什么要学这一节1. 二叉搜索树1.1 二叉搜索树概念1.2 二叉搜索树操作1.3 二叉搜索树的实现1.4 二叉搜索树的应用1.5 二叉搜索树的性能分析2. 经典题目2.1 最近公共祖先2.2 从前序与中序遍历序列构造二叉树2.3 二叉树的前序遍历&#xff08;非递归&#xff09;为什么要…

计算机组成原理复习:数据的表示和运算

计算机组成原理复习&#xff1a;数据的表示和运算2. 数据的表示和运算2.1 数制与编码2.1.1 数制&#xff1a;进位计数制及其相互转换2.1.2 编码&#xff1a;数值数据的编码与表示2.1.2.1 逻辑型数据2.1.2.2 字符型数据 之 ASCII码2.1.2.3 数值型数据 之 BCD码2.1.3 校验码——奇…

Part类 -- 上传文件

Part类 -- 上传文件一、核心方法1.1 HttpServletRequest 类方法1.2 Part 类方法二、代码示例前端搭配 form 表单&#xff1a;form input type “file”&#xff0c;允许通过浏览器选中一个文件上传给服务器。 Servlet 就支持处理这种上传文件的请求&#xff0c;把这个请求到的文…

安科瑞智能操控无线测温装置在江苏某化工产业园项目的应用

安科瑞 李亚俊 1 概述 江苏富强新材料有限公司是中国企业500强——山东金岭集团在江苏淮安盐化新材料产业园区投资设立的盐化工企业。公司将利用淮安丰富的盐矿资源和优越的发展环境&#xff0c;投资200亿元&#xff0c;建设120万吨/年离子膜烧碱项目、70万吨/年甲烷氯化物项…

vue新春游戏-拼手速抢车票小游戏,学习玩乐两不误,春节小游戏,新年小游戏

ue新春游戏-拼手速抢车票&#xff0c;老规矩&#xff0c;体验地址&#xff1a;http://game.pkec.net/word-ticket/。 写这个主要是前几天群里运营老师说咋没人写抢车票的&#xff0c;再加上我上一篇文章上了掘金一周&#xff0c;听说多上几次有证书&#xff0c;我还没搞到过掘金…

Go语言 函数传递:值传递 和 虚假的 “引用传递”

前言 其实从变量本身来说&#xff0c;go只有值传递&#xff0c;函数内的修改不会影响函数外。但有一种特例是指针&#xff0c;go可以传指针给函数&#xff0c;指针指向申请出来的实际内存&#xff0c;也就是保存元素的内存&#xff0c; 这样在函数内的修改&#xff0c;可以影响…

就算是TOP程序员,也有这些坏习惯

绝大多数程序员在职业生涯中&#xff0c;多多少少都会养成一些坏习惯&#xff0c;今天就来说一说身边最常见的一些坏习惯&#xff0c;也给刚入行的新朋友们提个醒&#xff0c;少走一些弯路。 那么&#xff0c;就让我们开始吧&#xff01; 1.不注意适当休息 比如日常工作时、…

B端产品-登录功能设计

在项目启动初期&#xff0c;基本大家都是先从账号体系先开始着手设计的&#xff0c;那么B端的登录功能如何设计呢&#xff1f; 一、需求分析 B端的产品的用户基本上可以分为内部员工和客户&#xff0c;如果是客户使用&#xff0c;基本上都会有注册功能&#xff1b;如果是内部员…

C# Console.Read读取回车和换行

C#的Console.Read函数&#xff1a; 读取缓冲区中的数据&#xff0c;读取到一个字符时停止。 C#的Console.ReadLine函数 读取缓冲区中的数据&#xff0c;遇到回车时停止。 Enter键&#xff1a; 将行数据输入缓冲区&#xff0c;并且将回车符和换行符 加入缓冲区。 注意 Consol…

【H5UI库和二维码】一.H5UI库;二.加密技术;三.二维码

目录​​​​​​​ 一.H5UI库 1.使用方法&#xff1a; &#xff08;1&#xff09;页面中引入css文件 &#xff08;2&#xff09;页面中引入js文件 2.组件的用法 &#xff08;2&#xff09;按钮的使用&#xff1a;button。有三种类型&#xff08;primary、danger、defaul…

MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《3》

前面了解到Faster R-CNN在实验中的效果很不错&#xff0c;以及对论文做了一个大概的了解&#xff0c;对此有兴趣的伙伴们也可以先浏览前面两篇文章&#xff1a;MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《1》MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《…