Ajax跨域访问Tomcat服务器

2016-12-16 18:57:48来源:CSDN作者:Leafage_M人点击

在学习jQuery的时候进行到AJax时,需要与服务器进行交互练习。我毫不犹豫的打开了我的Tomcat服务器运行起来,并使用普通的ajax方法访问运行中的服务器网址的时候,发现

XMLHttpRequest对象使用open和send后,在与onreadystatechange绑定的函数中检查到readyState为4,这说明请求已经完成且相应已经就绪,但是此时的status却提示为0。但是我查看W3CSchool发现这个status没有为0的说明。

下面是 XMLHttpRequest 对象的三个重要的属性:

属性描述
onreadystatechange存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState

存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。

  • 0: 请求未初始化
  • 1: 服务器连接已建立
  • 2: 请求已接收
  • 3: 请求处理中
  • 4: 请求已完成,且响应已就绪
status

200: "OK"

404: 未找到页面



为什么这个status会为0呢?我在网上查了查关于这status为0的情况。

stackoverflow上面的有关回答(原问题链接:http://stackoverflow.com/questions/2000609/jquery-ajax-status-code-0):

第一个情况:

It could be possible to get a status code of 0 if you have sent an AJAX call and a refresh of the browser was triggered before getting the AJAX response. The AJAX call will be cancelled and you will get this status.

第二个情况:

In my experience, you'll see a status of 0 when either doing cross-site scripting (where access is denied) or requesting a URL that is unreachable (typo, DNS issues, etc).

第三个情况:

Same problem here when using <button onclick="">submit</button>. Then solved by using <input type="button" onclick="">


这三个个大概已经能够说明了会出现status为0的情况。

大概就是这个意思:

1.我向服务器发出了ajax请求,在还没有取得响应的时候我就触发了浏览器刷新(可能是又输入了其他的URL或者认为刷新浏览器等各种情况),此时获取到的status码就为0。

2.就是访问的URL错误或者不存在,或者出现DNS问题等。

3.出现了跨域请求的问题。

4.修改方法是在原来的按钮button的type="submit"改成"button“,页面不立即跳转。(这里应该还是属于第一种刷新的情况)。


很显然,我遇到的问题并不是1、2、4。那就只能是跨域请求的问题了。

跨域请求的概念:

下面列出了一些属于跨域的情况(图片摘录于互联网): 
这里写图片描述


很显然,当端口不同、域名不同、协议不同的时候都属于跨域请求了。


我查看了下载个人电脑上跑的Tomcat服务器和测试ajax用的网址是不是属于跨域了。

Tomcat:http://localhost:8080/MyJavaWebApp/hello

ajax:http://localhost:49337/jQuery/Ajax/jQueryAjax.html?_ijt=ou23hf55psn5f10ogjgg1t7j1v


很明显,因为端口号的不同,这里发生了跨域请求。

当我将ajax和tomcat放在同一个端口下测试的时候确认能够访问到的。我这里在tomcat上用一个html代码测试ajax(两个端口都是8080)或者就普通的创建了一个html代码让ajax访问(两个端口都是49337),都能访问到。


那么如何去和跨域请求呢,我找到了两种方法,简单的记录一下。


1.使用XMLHttpRequest Level 2技术,也就是可以将不同的域名的服务器发出HTTP请求,这叫做“跨域资源共享”(Cross-origin resource sharing,简称CORS)。

使用这种方法相对来说比较简单容易实现,只需要浏览器支持这个功能,让服务器允许这种跨域操作。显然,浏览器的事插不上手,当然浏览器也会支持这种方法的。那么需要考虑的就是开发者的服务器上如何才能允许这种跨域操作。

servlet代码(这里将Servlet映射的URL设置为:http://localhost:8080/MyJavaWebApp/hello1):

package com.hello;import javax.servlet.*;import javax.servlet.http.*;import java.io.*;public class Hello2 extends HttpServlet {	public void doGet(HttpServletRequest request,HttpServletResponse response)	throws ServletException, IOException {				response.setHeader("Access-Control-Allow-Origin", "*");		response.setHeader("Access-Control-Allow-Methods", "POST,GET");		String username = request.getParameter("username");		String content = request.getParameter("content");				PrintWriter out = response.getWriter();		out.println("<html><head><title>hello</title></head>");		out.println("<body>");		out.println("<b>Hello," + username + "lalala</b>");		out.println("<b>Content:" + content + "</b>");		out.print("In HelloServlet");		out.println("</body></html>");				out.close();	}}

这里的

response.setHeader("Access-Control-Allow-Origin","*");和response.setHeader("Access-Control-Allow-Methods","POST,GET");

两行代码一个设置了允许访问的源点,也就是可以由哪里来进行访问,这里设置的“*”,就是允许所有的不同域来进行访问。如果只想指定某一个端口或者域来访问的话,可以设置为“http://localhost:49337”,这样只能是这个端口下的访问了。

另一个很明显就是设置了允许访问的方法,这里设置了GET和POST方法(有点问题就是我在这里测试的时候GET方法能够成功实现,二POST方法却依然访问不到)。


使用原生JavaScript访问(访问的就是上述servlet中的信息):

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Ajax</title></head><body>    <input type="button" value="提交" onclick="Ajax();">    <div id="resText"></div>    <script type="text/javascript">        var xmlHttpReq = null;        function Ajax() {            if(window.ActiveXObject) {                xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");            } else if (window.XMLHttpRequest) {                xmlHttpReq = new XMLHttpRequest();                xmlHttpReq.onreadystatechange = RequestCallBack;                xmlHttpReq.open("GET","http://localhost:8080/MyJavaWebApp/hello1?username=Leafage&content=nihao",true);                xmlHttpReq.send(null);            }        }        function RequestCallBack() {            if(xmlHttpReq.readyState == 4) {                if(xmlHttpReq.status == 200) {                    alert(xmlHttpReq.responseText);                }            }        }    </script></body></html>

使用jQuery中的$.ajax访问:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>jQueryAjax</title>    <script type="text/javascript" src="../jquery-3.1.1.js"></script>    <!--<script type="text/javascript" src="jQueryAjax.js"></script>--></head><body>    <input type="button" id="send" value="提交">    <script type="text/javascript" >        $(function () {            $("#send").click(function () {                $.ajax({                    type : "GET",                    url : "http://localhost:8080/MyJavaWebApp/hello1?username=Leafage&content=nihao",                    dataType : "html",                    success : function(data,textStatus) {                        alert(data);                        alert(textStatus);                    },                    error : function () {                        alert("Error!");                    }                })            })        })    </script></body></html>


成功访问:



有关CORS技术的详解参考:

http://www.ruanyifeng.com/blog/2016/04/cors.html

https://github.com/hstarorg/HstarDoc/blob/master/%E5%89%8D%E7%AB%AF%E7%9B%B8%E5%85%B3/CORS%E8%AF%A6%E8%A7%A3.md



2.使用JSONP技术。

先说说JSONP是怎么产生的:

其实网上关于JSONP的讲解有很多,但却千篇一律,而且云里雾里,对于很多刚接触的人来讲理解起来有些困难,小可不才,试着用自己的方式来阐释一下这个问题,看看是否有帮助。

1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;

2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>);

3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;

4、恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;

5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。

6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。

7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

参考:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html


简单点就是,直接ajax访问html等资源不允许,但是访问js文件的时候却是可以通过的。而正好有一种JSON的数据格式可以传输数,所以将数据作为JSON进行传输访问。然后回调函数进行操作。

jQuery代码:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>jQueryAjax</title>    <script type="text/javascript" src="../jquery-3.1.1.js"></script>    <!--<script type="text/javascript" src="jQueryAjax.js"></script>--></head><body>    <input type="button" id="send" value="提交">    <script type="text/javascript" >        $(function () {            $("#send").click(function () {                $.ajax({                    type : "GET",                    data : {"username":"Leafage","content":"nihao"},                    url : "http://localhost:8080/MyJavaWebApp/hello",                    dataType : "jsonp",                    jsonp : "callback",                    jsonpCallback : "jsonpCallback",                    success : function(data,textStatus) {                        alert(data);                        alert(textStatus);                    },                    error : function () {                        alert("Error!");                    }                })            })        })        function jsonpCallback(data) {            alert("这里是回调的jsonpCallback函数!");            alert("接收的数据为:" + data);        }    </script></body></html>

这里使用$.ajax方法进行了ajax请求。

jsonp:传递给请求服务器页面的,用来获得需要回调的函数名字,一般默认为callback,所以这个可以省略,所以作为key。

jsonpCallback:访问成功后需要回调的函数名,作为value。

所以这里的jsonp和jsonpCallback的基本形式就是:callback=jsonpCallback,在后台代码中可以通过callback得到jsonpCallback,也就是需要回调的函数的名字。

执行成功之后,优先调用jsonpCallback函数,里面的参数就是后台传过来的数据,可以在里面处理。然后执行success里面的内容。(注意:这里需要回调的函数不要写在ajax的相关函数里面去,否则无法执行,这里不能写在$(function(){})函数里面,写在外面就能调用。)

Servlet代码:

package mypack;import javax.servlet.*;import javax.servlet.http.*;import java.io.*;public class HelloServlet extends HttpServlet {	public void doGet(HttpServletRequest request,HttpServletResponse response)	throws ServletException, IOException {				String username = request.getParameter("username");		String content = request.getParameter("content");				String callbackName = request.getParameter("callback");		String returnString = callbackName + "('" + username +  content + "')";				response.setContentType("text/html;charset=utf-8");				PrintWriter out = response.getWriter();						out.print(returnString);						out.close();			}}

后台在根据callback得到需要回调的函数之后,将相关数据输入传入其中即可。


测试成功:


这里的CORS和JSONP都只是简单的实现而已,还有其他具体的差异和扩展内容。

当然跨域的方法也有其他的。

这里的内容仅做参考。


最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台