• Ajax及跨域请求


    视频

    1. JavaScript中的Ajax

    1.1 功能

    实现网页的动态展示。刷新网页中的部分页面内容,又不引起整个页面的刷新。

    • 完整代码:
    	     let xmlHttpRequest = new XMLHttpRequest();
    		 xmlHttpRequest.onreadystatechange = function () {
             	if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200){
                 	var text = xmlHttpRequest.responseText;//服务器返回的字符串
                 	console.log(text)
                  //ToDo
              }
            }
            //GET请求发送数据:getText="/资源路径?key1=value&key2=value"
            xmlHttpRequest.open("GET",getText,true);
            xmlHttpRequest.send(); 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1.2 步骤详解(GET请求)

    1. 创建XMLHttpRequest对象
            let xmlHttpRequest = new XMLHttpRequest();
           
    
    • 1
    • 2
    1. 状态码发生改变onreadystatechange

    xmlHttpRequest.readyState返回0-4,5个值,代表xmlHttpRequest 对象的5种不同状态:
    0:xmlHttpRequest 对象的未初始化状态。这个值检测不到;
    1: xmlHttpRequest对象使用open方法,创建了Http请求;
    2: xmlHttpRequest对象使用send方法,处于发送数据状态;
    3: 客户端已经返回数据,xmlHttpRequest对象正在接收数据的状态;
    4:数据接收完毕

    xmlHttpRequest.status 返回响应状态码,200表示响应成功

    xmlHttpRequest.responseText返回Response响应的字符串。

     		xmlHttpRequest.onreadystatechange = function () {
              if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200){
                  var text = xmlHttpRequest.responseText;//服务器返回的字符串
                  //ToDo
              }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 初始请求数据
      XMLHttpRequest.open(method,URL,flag,name,password);
      参数:
      - method:请求方式GET | POST
      - URL:路径
      - flag: true异步请求;false同步请求。默认为true
      - name:服务器用户名
      - password: 服务器密码

      同步:在第4步发送请求之后,必须等待服务器将数据返回,在此期间不能执行其他任务。
      异步:在第4步发送请求之后,执行其他任务,无需等待数据返回。

            xmlHttpRequest.open("get",getText,true);
    
    • 1
    1. 发送请求
            xmlHttpRequest.send(); 
    
    • 1

    1.3 通过POST请求发送表单

    与GET请求有两个不同的地方

    1. 需要设置请求头:
      代码必须在open方法和send方法中间
    	xmlHttpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8")
    
    • 1
    1. 发送数据的位置
    	xmlHttpRequest.send("key1=value&key2=value");
    
    • 1

    1.3.1 POST请求时发送到服务器的各种数据格式

    1. JSON数据格式application/json
    xhr.setRequestHeader("Content-type","application/json; charset=utf-8");
    
    • 1
    1. 提交 form 表单 application/x-www-form-urlencoded
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
    
    • 1
    1. 通过form表单发送文件multipart/form-data
    xhr.setRequestHeader("Content-type", "multipart/form-data; charset=utf-8");
    
    • 1
    1. 发送数据为xml格式text/xml
    xhr.setRequestHeader("Content-type", "text/xml; charset=utf-8");
    
    • 1

    1.4 返回的json格式如何处理

    服务器返回的数据都是字符串格式,处理方法:

    1. eval方法
    	var jsonObj = eval('('+jsonStr+')');//将json字符串jsonStr转换为jasn对象
    	var value = jsonObj.key1;//返回json对象中键值为key1的值
    
    • 1
    • 2
    1. JSON.prse
    	var jsonObj = JSON.parse(jsonStr);//将json字符串jsonStr转换为jasn对象
    
    • 1

    1.5 通过ajax发送请求和接收响应时乱码问题

    • Tomcat 10 没有任何乱码问题
    • Tomcat 9 及以下
    1. Get 请求:Response响应返回中文乱码
      解决办法,服务器端加入以下代码:
    	response.setContentType("text/html;charset=UTF-8");
    
    • 1
    1. POST请求:在请求和响应中文时都有乱码问题
      解决办法:
    	request.setCharacterEncoding(UTF-8);//解决请求乱码
    	response.setContentType("text/html;charset=UTF-8");//解决响应乱码
    
    • 1
    • 2

    2. JQuery中的Ajax

    详细的讲解
    第一种:(参数最少的写法)

    	$.ajax({
              url:"路径",
              data: {
                    id: 1,
                },
              success:function (data) {
                $.each(data,function (i,n) {
                    // each可以循环json格式的字符串,i为index,n为json的数据,取值:n.name
                })
              }
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    $.each(data,function (i,n)的参数:

    1. data为一维的数组或json对象时:i是key,n是value
    2. data为二位的数组或json对象是List集合时:i是下标,ndata[i]
    参数名类型描述
    urlString(默认: 当前页地址) 发送请求的地址。
    typeString(默认: “GET”) 请求方式 (“POST” 或 “GET”), 默认为 “GET”。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。
    asyncBoolean(默认: true) 默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
    contentTypeString(默认: “application/x-www-form-urlencoded”) 发送信息至服务器时内容编码类型。默认值适合大多数应用场合。告诉服务器从浏览器提交过来的数据格式。
    dataObject、String发送到服务器的数据。json格式
    dataTypeString预期服务器返回的数据类型。json、string
    errorFunction(默认: 自动判断 (xml 或 html)) 请求失败时将调用此方法。这个方法有三个参数:XMLHttpRequest 对象,错误信息,(可能)捕获的错误对象。
    successFunction请求成功后回调函数。这个方法有两个参数:服务器返回数据,返回状态
    beforeSendFunction请求发起前执行
    completeFunction请求完成后执行,无论成功与否
    • 第二种
      $.get(“url”,{ data(key:value) },callback,“type”);
      $.post(“路径”,{ “数据名”:数据 },function(返回的数据){ 执行代码 },“数据格式”)

    默认数据格式为json,可省略,get请求最简化写法:

    	$.get("路径",function(返回的数据){ 执行代码 })
    
    • 1
    参数名称类型说明
    urlString请求HTML页的URL地址
    data(可选)Object发送到服务器的key/value数据会作为字符串附加到请求的URL中
    callback(可选)Function请求成功时的回调函数,有两个参数:返回的数据,请求状态
    type(可选)String服务器返回内容的格式:xml、html、script、json、text、default

    3. 跨域请求

    Ajax发送跨域请求时会被浏览器的同源策略(CORS)阻止,这是浏览器的安全策略。

    总结:实现跨域请求必须服务器端配合,浏览器端无法单独实现跨域请求

    示例
    a站点:http://localhost:8080/a/
    b站点:http://localhost:8081/b/
    从a站点发送跨域请求到b站点,浏览器报错:

    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.
    
    • 1

    什么是同源?
    协议一致、域名一致、端口号一致。

    3.1 在servlet端设置响应头

    要访问的资源允许跨域访问。

    //允许某个站点可以对本地资源跨域访问
    response.setHeader("Access-Control-Allow-Origin","http://localhost:8080");
    // 允许所有站点可以对本地资源跨域访问
    response.setHeader("Access-Control-Allow-Origin","*");
    
    • 1
    • 2
    • 3
    • 4

    3.2 jsonp

    1. jsonp不是Ajax请求,通过代码实现了类似Ajax局部刷新的效果。
    2. jsonp是利用了<script>标签的src属性。
    3. script加载时,会将src属性的值所指向的文件内容作为script代码执行,实现ajax的效果。
    4. 只能实现get请求。

    3.2.1 简单示例

    b中servlet返回的字符串,会在a的页面中当作script代码执行

    a的web

    <script type="text/javascript" src="http://localhost:8081/b/AjaxJsonp1"></script>
    
    • 1

    b的servlet

    @WebServlet("/AjaxJsonp1")
    public class AjaxJsonp1 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
            response.getWriter().print("alert(\"Jsonp1!\")");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.2.2 复杂示例

    执行过程

    1. 页面加载完毕后,点击button按钮
    2. body中增加script元素
    3. script元素加载时会加载自己的src属性,src属性指向b站点的ajaxjsonp2,并且通过get方法传递值fun=sayHello
    4. b 站点获取请求中的值sayHello,并返回了字符串sayHello({{"username":"jackson"}})
    5. 返回的字符串会被script元素当作script代码执行。
    6. 执行sayHello(data)方法

    a站点中的页面

    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <script type="text/javascript">
        function sayHello(data){
            // 获取json字符串中的key对应的value,添加到div1中
            document.getElementById("div1").innerHTML = data.username
        }
    </script>
    <script type="text/javascript">
        window.onload = function () {
            document.getElementById("btn").onclick = () => {
                // 创建script元素
                const htmlScriptElement = document.createElement(`script`)
                // 设置script的type属性
                htmlScriptElement.type = "text/javascript"
                // 设置script的src属性,注意:通过get方法传入了参数fun=sayHello
                htmlScriptElement.src = "http://localhost:8081/b/ajaxjsonp2?fun=sayHello"
                // 将script元素添加到body中
                document.getElementsByTagName("body")[0].appendChild(htmlScriptElement)
            }
    
        }
    </script>
    <button id="btn">通过jsonp调用方法</button>
    <div id="div1"></div>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    b站点中的servlet

    @WebServlet("/ajaxjsonp2")
    public class AjaxJsonp2 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            // get传入参数,获取参数的值
            String fun = request.getParameter("fun");
            // 返回的值是字符串
            response.getWriter().print(fun + "({\"username\":\"jackson\"})");
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    页面点击button后的代码:

    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <script type="text/javascript">
        function sayHello(data){
            // 获取json字符串中的key对应的value,添加到div1中
            document.getElementById("div1").innerHTML = data.username
        }
    </script>
    <script type="text/javascript">
        window.onload = function () {
            document.getElementById("btn").onclick = () => {
                // 创建script元素
                const htmlScriptElement = document.createElement(`script`)
                // 设置script的type属性
                htmlScriptElement.type = "text/javascript"
                // 设置script的src属性,注意:通过get方法传入了参数fun=sayHello
                htmlScriptElement.src = "http://localhost:8081/b/ajaxjsonp2?fun=sayHello"
                // 将script元素添加到body中
                document.getElementsByTagName("body")[0].appendChild(htmlScriptElement)
            }
    
        }
    </script>
    <button id="btn">通过jsonp调用方法</button>
    <-- dia-->
    <div id="div1">jackson</div>
    <-- 点击button后会在body最后增加子元素 script,script元素在加载时会加载src的属性值-->
    <script type="text/javascript" src="http://localhost:8081/b/ajaxjsonp2?fun=sayHello"></script>
    
    </body>
    </html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3.3 jQuery封装的jsonp

    1. jQuery封装的jsonp看似与ajax一样,但它只是使用了ajax的外壳
    2. dataTape属性值:jsonp
    3. 在发送请求时浏览器中请求url:请求 URL: http://localhost:8081/b/ajaxjson3?callback=jQuery36007791340332230894_1656146765961&_=1656146765962,jquery自动生成键值对,键的名字默认为callback,键值对的默认值为随机字符串,并通过get方法传递给后台。后面的_=1656146765962为时间戳,防止浏览器读取缓存。
    4. servlet中需要获取该键值对的value,然后返回给浏览器。返回的数据:jQuery36007791340332230894_1656146765961({"username":"jackson"})
    5. 可以看出jquery实现jsonp和上面3.2.2中使用的方法是一样的,jquery把方法名和方法都进行了优化。

    a站点网页

    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <script type="text/javascript" src="js/jquery-3.6.0.js"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn").click(function () {
                $.ajax({
                    type: "GET",
                    url: "http://localhost:8081/b/ajaxjson3",
                    dataType: "jsonp",// 返回数据的格式
                    success: function (data) {// data:返回的数据
                        $("#div1").html(data.username)
                    }
                })
            })
        })
    </script>
    <button id="btn">jQuery实现jsonp</button>
    <div id="div1"></div>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    b站点servlet

    @WebServlet("/ajaxjson3")
    public class AjaxJsonp3 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // jquery在get请求中添加键值对,key是callback,value为随机字符串
            String callback = request.getParameter("callback");
            response.getWriter().print(callback+"({\"username\":\"jackson\"})");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • a站点页面中ajax的另一种写法
    1. ajax发送请求时,请求 URL: 请求 URL: http://localhost:8081/b/ajaxjson4?fun=sayHello&_=1656148497823
    2. 不使用默认的参数名callback,指定为fun
    3. 不使用默认的回调函数success,指定回调函数为sayHello
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <script type="text/javascript" src="js/jquery-3.6.0.js"></script>
    <script type="text/javascript">
        function sayHello(data){
            $("#div1").html(data.username)
        }
        $(function () {
            $("#btn").click(function () {
                $.ajax({
                    type: "GET",
                    url: "http://localhost:8081/b/ajaxjson4",
                    dataType: "jsonp",// 指定数据类型为jsonp
                    jsonp:"fun", // 指定GET请求时参数的key为callback
                    jsonpCallback:"sayHello" // 指定jsonp的回调函数为sayHello
                })
            })
        })
    </script>
    <button id="btn">jQuery实现jsonp</button>
    <div id="div1"></div>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    b站点中的servlet

    @WebServlet("/ajaxjson4")
    public class AjaxJsonp4 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String funName = request.getParameter("fun");
            response.getWriter().print(funName+"({\"username\":\"jackson\"})");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    FAQ (Kubernetes the hard way)
    能够1年涨薪2次的软件测试工程师,他到底强在哪里?
    自动化测试 —— Pytest fixture及conftest详解!
    线性代数本质系列(一)向量,线性组合,线性相关,矩阵
    青少年软件编程C++二级题库(51-60)
    mysql出现提示错误10061的解决方法
    abp(net core)+easyui+efcore实现仓储管理系统——ABP升级7.3上(五十八)
    深入分析以太坊合并后的监管和应用层问题
    EventLoop
    Tkinter学习笔记(一):完成文件选择和保存对话框
  • 原文地址:https://blog.csdn.net/YUELEI118/article/details/125454912