Ajax跨域问题

来源:互联网 发布:优酷淘宝搞笑视频 编辑:程序博客网 时间:2024/05/18 00:21

场景:我们想订阅新浪博客,如下图:
这里写图片描述

此时我们使用java代码,对订阅地址发出Ajax请求。
代码演示Ajax跨域请求:
rss.jsp

<%--  Created by IntelliJ IDEA.  User: John  Date: 2017/7/20  Time: 22:27  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><link><meta>    <meta charset="utf-8">    <title>Ajax跨域</title>    <link rel="stylesheet" href="/static/css/bootstrap.min.css"></head><body>    <div class="container">        <div class="page-header">            <h3>RSS</h3>        </div>        <input type="text" id="url" class="col-xs-5">        <button id="loadBtn">Load</button>        <ul class="list-unstyled" id="list">        </ul>    </div>    <script>        (function(){            function createXmlHttp(){                var xmlHttp = null;                if(window.ActiveXObject){                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");                }else{                    xmlHttp = new XMLHttpRequest();                }                return xmlHttp;            }            document.querySelector("#loadBtn").onclick = function(){                //document.querySelector("list").innerHTML = "";                var url = document.querySelector("#url").value;                var xmlHttp = createXmlHttp();                xmlHttp.open("get",url,true);                xmlHttp.send();            }        })();    </script></body></html>

这里写图片描述

JS同源策略,为了安全考虑,不能跨域名访问。

解决方案
一.使用代理模式
这里写图片描述

使用第三方组件Apache HttpComponenets
HttpClient的测试代码

package com.wh.test;import org.apache.commons.io.IOUtils;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 org.junit.Test;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;/** * Created by John on 2017/7/20. */public class HttpClientTest{        @Test        public void testDownloadImage() throws IOException {            CloseableHttpClient httpClient = HttpClients.createDefault();            HttpGet httpGet = new HttpGet("http://ww4.sinaimg.cn/mw690/6f055540gw1eqw4zp7hsgj21kw2dcqv5.jpg");            HttpResponse httpResponse = httpClient.execute(httpGet);            //获取HTTP请求的相应码            int httpCode = httpResponse.getStatusLine().getStatusCode();            if(httpCode == 200) {                //获取图片的字节流                InputStream inputStream = httpResponse.getEntity().getContent();                FileOutputStream outputStream = new FileOutputStream("D:/xiaoqingxin.jpg");                IOUtils.copy(inputStream,outputStream);                outputStream.flush();                outputStream.close();                inputStream.close();            } else {                System.out.println("请求异常:" + httpCode);            }            httpClient.close();        }        @Test        public void testGetRequest() throws IOException {            CloseableHttpClient httpClient = HttpClients.createDefault();            HttpGet httpGet = new HttpGet("http://blog.sina.com.cn/rss/1220218113.xml");            HttpResponse httpResponse = httpClient.execute(httpGet);            //获取HTTP请求的相应码            int httpCode = httpResponse.getStatusLine().getStatusCode();            if(httpCode == 200) {                //获取网页的字符流                InputStream inputStream = httpResponse.getEntity().getContent();                String html = IOUtils.toString(inputStream); //将inputstream转换为字符串                System.out.println(html);            } else {                System.out.println("请求异常:" + httpCode);            }            httpClient.close();        }    }

HttpClient操作工具类

package com.wh.util;import org.apache.commons.io.IOUtils;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.FileOutputStream;import java.io.IOException;import java.io.InputStream;public class HttpUtil {    public static String getRequestText(String url) {        CloseableHttpClient httpClient = HttpClients.createDefault();        try {            HttpGet httpGet = new HttpGet(url);            HttpResponse httpResponse = httpClient.execute(httpGet);            //获取HTTP请求的相应码            int httpCode = httpResponse.getStatusLine().getStatusCode();            if(httpCode == 200) {                //获取网页的字符流                InputStream inputStream = httpResponse.getEntity().getContent();                String html = IOUtils.toString(inputStream); //将inputstream转换为字符串                return html;            } else {                throw new RuntimeException("请求服务器异常:" + httpCode);            }        } catch (IOException e) {            throw new RuntimeException(e);        } finally {            try {                httpClient.close();            } catch (IOException e) {                throw new RuntimeException(e);            }        }    }    public static void getRequestStream(String url,String savePath) {        CloseableHttpClient httpClient = HttpClients.createDefault();        try {            HttpGet httpGet = new HttpGet(url);            HttpResponse httpResponse = httpClient.execute(httpGet);            //获取HTTP请求的相应码            int httpCode = httpResponse.getStatusLine().getStatusCode();            if(httpCode == 200) {                //获取图片的字节流                InputStream inputStream = httpResponse.getEntity().getContent();                FileOutputStream outputStream = new FileOutputStream(savePath);                IOUtils.copy(inputStream,outputStream);                outputStream.flush();                outputStream.close();                inputStream.close();            } else {                throw new RuntimeException("请求服务器异常:" + httpCode);            }            httpClient.close();        } catch (IOException e) {            throw new RuntimeException(e);        } finally {            try {                httpClient.close();            } catch (IOException e) {                throw new RuntimeException(e);            }        }    }}

使用代理模式后:
rss.jsp

<%--  Created by IntelliJ IDEA.  User: John  Date: 2017/7/20  Time: 22:27  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><link><meta>    <meta charset="utf-8">    <title>Ajax跨域</title>    <link rel="stylesheet" href="/static/css/bootstrap.min.css"></head><body>    <div class="container">        <div class="page-header">            <h3>RSS</h3>        </div>        <input type="text" id="url" class="col-xs-5">        <button id="loadBtn">Load</button>        <ul class="list-unstyled" id="list">        </ul>    </div>    <script>        (function(){            function createXmlHttp(){                var xmlHttp = null;                if(window.ActiveXObject){                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");                }else{                    xmlHttp = new XMLHttpRequest();                }                return xmlHttp;            }            function createLi(link,title){                var li = document.createElement("li");                var a = document.createElement("a");                var text = document.createTextNode(title);                a.setAttribute("href",link);                a.setAttribute("target","_blank");                a.appendChild(text);                li.appendChild(a);                document.querySelector("#list").appendChild(li);            }            document.querySelector("#loadBtn").onclick = function(){                //document.querySelector("list").innerHTML = " ";                var url = document.querySelector("#url").value;                var xmlHttp = createXmlHttp();                xmlHttp.open("get","/load?url="+url,true);                xmlHttp.onreadystatechange = function(){                  if(xmlHttp.readyState == 4){                      if(xmlHttp.status == 200){                          var xmlDoc = xmlHttp.responseXML;                          var itemArray = xmlDoc.getElementsByTagName("item");                          for(var i = 0;i < itemArray.length;i++){                              var item = itemArray[i];                              var title = item.getElementsByTagName("title")[0].childNodes[0].nodeValue;                              var link = item.getElementsByTagName("link")[0].childNodes[0].nodeValue;                              createLi(link,title);                          }                      }                  }                };                xmlHttp.send();            }        })();    </script></body></html>

后端servlet代理跨域访问

package com.wh.web;import com.wh.util.HttpUtil;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;/** * Created by John on 2017/7/20. * Ajax跨域请求代理Servlet */@WebServlet("/load")public class LoadServlet extends HttpServlet{    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        String url = req.getParameter("url");//"http://blog.sina.com.cn/rss/1220218113.xml"        String xml = HttpUtil.getRequestText(url);        resp.setContentType("text/xml;charset=UTF-8");        PrintWriter writer = resp.getWriter();        writer.print(xml);        writer.flush();        writer.close();    }}

这里写图片描述

场景2:电子词典(使用有道翻译API接口)
dict.jsp

<%--  Created by IntelliJ IDEA.  User: John  Date: 2017/7/21  Time: 22:11  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <meta charset="UTF-8">    <title>Document</title>    <link rel="stylesheet" href="/static/css/bootstrap.min.css"></head><body>    <div class="container">        <div class="page-header">            <h3>电子词典</h3>        </div>        <div class="form-group">            <input type="text" id="keyword" class="form-control" placeholder="请输入要查询的单词">        </div>    </div>    <p id="result"></p>    <script>        (function(){            function createXmlHttp() {                var xmlHttp = null;                if(window.ActiveXObject) {                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");                } else {                    xmlHttp = new XMLHttpRequest();                }                return xmlHttp;            }            document.querySelector("#keyword").onkeyup = function(event){                if(13 == event.keyCode){                    var keyword = this.value;                    var xmlHttp = createXmlHttp();                    xmlHttp.open("get","/dict?q=" + encodeURIComponent(keyword),true);                    xmlHttp.onreadystatechange = function(){                        if(xmlHttp.readyState == 4){                            if(xmlHttp.status == 200){                                var xmlDoc = xmlHttp.responseXML;                                var basic = xmlDoc.getElementsByTagName("basic")[0];                                var explains = basic.getElementsByTagName("explains")[0];                                var ex = explains.getElementsByTagName("ex")[0].childNodes[0].nodeValue;                                document.querySelector("#result").innerText = ex;                            }                        }                    };                    xmlHttp.send();                }            }        })();    </script></body></html>
package com.wh.web;import com.wh.util.HttpUtil;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;/** * Created by John on 2017/7/21. */@WebServlet("/dict")public class DictServlet extends HttpServlet{    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        String keyword = req.getParameter("q");        keyword = new String(keyword.getBytes("ISO8859-1"),"UTF-8");        String url = "http://fanyi.youdao.com/openapi.do?keyfrom=kaishengit&key=1587754017&type=data&doctype=xml&version=1.1&q=" + keyword;        String xml = HttpUtil.getRequestText(url);        resp.setContentType("text/xml;charset=UTF-8");        PrintWriter writer = resp.getWriter();        writer.print(xml);        writer.flush();        writer.close();    }}

二.使用JSONP
JSONP(JSON with Padding),用来解决跨域问题的另一种解决方案,需要服务器端的支持。
JS中邪恶的eval()函数
jsonp.jsp

<%--  Created by IntelliJ IDEA.  User: John  Date: 2017/7/24  Time: 22:26  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <meta charset="UTF-8">    <title>Document</title></head><body><script src="/static/js/jquery-1.11.3.min.js"></script><button id="btn">翻译</button><script>    $("#btn").click(function(){        $.get("/jsonp",{"callback":"handler"}, function (data) {            eval(data);//此处,eval()会执行括号里的代表回调函数的参数字符串,即自动执行handler(data)        });    });    function handler(data){        console.log("callback:" + data.id + "->" + data.name + "->" + data.address + "->" + data.score);    }</script></body></html>

引申:JQuery对JSONP的支持

$("#btn").click(function(){$.getJSON("/jsonp?callback=?",function(data){alert(data.name);});});

JQuery会自动将callback后面的问号替换成生成的函数名称
这里写图片描述

服务端的支持
JsonpServlet.java

package com.wh.web;import com.google.gson.Gson;import com.wh.DTO.User;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;/** * Created by John on 2017/7/24. */@WebServlet("/jsonp")public class JsonpServlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        //String callback = req.getParameter("callback");        //服务端约定回调函数名为handler        User user = new User(1,"lisi","China",77F);        String data = new Gson().toJson(user);        PrintWriter writer = resp.getWriter();        writer.print("handler(" + data + ")");        //writer.print(callback + "(" + data + ")");        writer.flush();        writer.close();    }}

使用JSONP直接在jsp中跨域访问有道翻译API
原理:JSONP(JSONWithPadding),就是打包在函数调用中的的JSON(或者包裹的JSON)。JSON是一种数据格式,JSONP是一种数据调用方式。//JSON{“name”:“sb”}//JSONPcallback({“name”:“sb”})出于安全考虑,脚本(AJAX)不能访问非本域的内容。但是,静态资源是不受域策略限制的,可以加载任意域的脚本、样式、图片等静态资源,JSOP就是利用这种原理来实现跨域获取数据的。

<%--  Created by IntelliJ IDEA.  User: John  Date: 2017/7/24  Time: 22:26  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <meta charset="UTF-8">    <title>Document</title></head><body><script src="/static/js/jquery-1.11.3.min.js"></script><input type="text" id="keyword"><button id="btn">翻译</button><p id="result"></p><script>    $(function(){        //使用JSOP进行跨域访问(有道词典API接口)        $("#btn").click(function(){            var url = "http://fanyi.youdao.com/openapi.do?keyfrom=kaishengit&key=1587754017&type=data&doctype=jsonp&callback=?&version=1.1";            var keyword = $("#keyword").val();            console.log(typeof keyword);//string            keyword = keyword === undefined || keyword == ""? "undefined":keyword            //jQuery中JSONP的两种实现方式            //第一种方式           /* $.ajax({                type:"get",                url: url,                dataType:"jsonp",                jsonp:"callallback",//指定回调函数,名字可以随意取,但必须与下一行的Get参数一致                data:"q="+ keyword,                success: function (json) {                    var array = json.basic.explains;                    var str = "";                    for(var i = 0;i < array.length;i++){                        str += array[i] + "</br>";                    }                    $("#result").html(str);                }            });*/            //第二种方式            $.getJSON(url,{"q":keyword},function(json){                var array = json.basic.explains;                var str = "";                for(var i = 0;i < array.length;i++){                    str += array[i] + "</br>";                }                $("#result").html(str);            });        });       /* $.getJSON("/jsonp?callback=?",function(result){            console.log("name:" + result.name);        });        $("#btn").click(function(){            $.get("/jsonp",{"callback":"handler"}, function (data) {                eval(data);//此处,eval()会执行括号里的代表回调函数的参数字符串,即自动执行handler(data)            });        });        function handler(data){            console.log("callback:" + data.id + "->" + data.name + "->" + data.address + "->" + data.score);        }*/    });</script></body></html>
原创粉丝点击