Ajax跨域和JSONP

前端之家收集整理的这篇文章主要介绍了Ajax跨域和JSONP前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这几天做一个服务,主要是提供api给别人调用,首先我在自己的机器上调通了接口,然后把api给了他们,自然地像 http://localhost:8081/bizcenter/servlet/fileUpload 的url,要把localhost改成我的ip,比如 http://172.16.30.61:8081/bizcenter/servlet/fileUpload,结果就出现了“跨域”的问题。噢,第一次这么直接地面对跨域~换成了127.0.0.1,firefox也提示

拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8081/bizcenter/servlet/checkNotdonebiz 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。

说到这里,我决定先理解清楚localhost和127.0.0.1之间的区别。以前只知道两个是等价的可互换,具体区别说不出。
localhost也叫local ,正确的解释是:本地服务器
127.0.0.1在windows等系统的正确解释是:本机地址(本机服务器)
他们的解析通过本机的host文件,windows自动将localhost解析为127.0.0.1
localhot(local)是不经网卡传输!这点很重要,它不受网络防火墙和网卡相关的的限制。
127.0.0.1是通过网卡传输,依赖网卡,并受到网络防火墙和网卡相关的限制。
一般设置程序时本地服务用localhost是最好的,localhost不会解析成ip,也不会占用网卡、网络资源。
有时候用localhost可以,但用127.0.0.1就不可以的情况就是在于此。猜想localhost访问时,系统带的本机当前用户的权限去访问,而用ip的时候,等于本机是通过网络再去访问本机,可能涉及到网络用户的权限。

所以,%System32%/driver/etc/host中增加一条 127.0.0.1 localhost,就可以作个映射。

说完了localhost和127.0.0.1,再回来跨域。什么时候会出现这个情况呢
借一下网上的图,JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象,同一域名下叫同源。所以你自己的web项目中所有的ajax请求本应用的所有接口,都是同源。如果ajax其他域名上的接口,那就不行了。



说说一些解决办法吧。前端和后台都有办法。
1、后台代理
既然直接用ajax去访问不同域的资源行不通,但是后台代码用Http工具类访问任何Url都是正常的,可以写一个proxy(如servlet),把要访问的跨域url用Ajax方法提交给本应用的proxy,然后proxy中再用HttpUrlConnection或HttpClient模拟http去访问跨域的url,获取到结果后再write回去。

public class ProxyServlet extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException {
		doPost(req,resp);
	}

	@Override
	protected void doPost(HttpServletRequest req,IOException {
		String text = IoUtils.toString(req.getInputStream(),"utf-8");
		//resp.setHeader("Access-Control-Allow-Origin","http://172.16.30.163:8088");
		String url= req.getParameter("proxy_url");
		String res = post(<span class="errorMessage "></span>url,text);
		resp.getWriter().write(res);
	}
	private String post(String url,String data){
		HttpPost post = new HttpPost(url);
		post.setHeader("Content-Type","text/html;charset=UTF-8");
		String responseMsg = null;
		try {
			DefaultHttpClient httpclient = new DefaultHttpClient();
			ByteArrayEntity e = new ByteArrayEntity(data.getBytes("UTF-8"));
			post.setEntity(e);
			HttpResponse r = httpclient.execute(post);
			HttpEntity entity = r.getEntity();
			if (r.getStatusLine().getStatusCode() == 200) {
				responseMsg = EntityUtils.toString(entity,"UTF-8");
			} else {
				System.out.println("访问出错:" + url);
			}
		} catch (Exception e) {
		} finally {
			post.releaseConnection();
		}
		return responseMsg;
	}
}
这种办法还不错,不过会加重后台的负担,因为每次都要多一次http请求。


2、JSONP
JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
这是因为众所周知的<script>标签可以加载任何 url 上的资源,我们经常在<head></head>中用script引入各种js,或是本地的,或是远程的。如百度库的jquery
<script typet="text/javascript" src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>。

我们做个简单的演示。有一个远程url--> http://localhost:8080/pro1/a.action,上面的资源是一个json串{"name":"我来自pro1"}。我还有一个应用http://localhost:8081/pro2/b.html,从b.html到a.action是跨域的。 在b.html中构建并执行一段js:
function CreateScript() {
    var src = http://localhost:8080/pro1/a.action;
  $("<script><//script>").attr("src",src).appendTo("body");
}
在控制台可以看见报js语法错误了。原来用script标签加载完后,会立即把响应结果当js语句去执行,很明显 {"name":"我来自pro1"} 不是合法的js语句啊。但如果是返回的是jsonpcallback({"name":"我来自pro1"}),只要有jsonpcallback这个方法,就是合法的语句了。服务端怎么知道你页面上定义了什么方法啊对不对。我们可以告诉服务端嘛,http://localhost:8080/pro1/a.action?callback=jsonpcallback。这样服务端获取callback参数,在返回的时候,把JSON再包一层callback,变成jsonpcallback({"name":"我来自pro1"})就行了。
是的,没错。这就是JSONP的原理。

这是最原始的写法,谁正直会去写这么多啰嗦的代码来实现一个功能还不好维护。所以Jquery提供了Jsonp的快捷方式。
    $.ajax({ 
            url : "http://localhost:8080/pro1/a.action?callback=jsonpcallback",type : "post",data : {"cust_id":1},async : true,dataType : "jsonp",jsonp:"jsonpcallback",//jsonpCallback:"fff",error : function(XMLHttpRequest,textStatus,errorThrown) {
            },success : function(data) {
                console.log(data);
            }
        });      
这里有两个属性要注意一下。
jsonp:指明回调函数的参数名,这个名字是要在request.getParameter()中用的。你写的jsonpcallback,那getParameter()就要用jsonpcallback。
jsonpCallback:如果不指定这个,可以看到jquery是随机建了一个方法叫做jQuery19101256806997398623_1464157164926。
http://localhost:8080/pro1/a.action?jsonpcallback=jQuery19101256806997398623_1464157164926&cust_id=1。我们可以指定方法名,这样管理请求更容易,也能方便地提供回调函数错误处理。你也可以在想让浏览器缓存GET请求的时候,指定这个回调函数名。比如设成 jsonCallbakk:deal,就变成
http://localhost:8080/pro1/a.action?jsonpcallback=deal&cust_id=1
其底层的实现,估计是这样
function success_jsonpCallback(data) { success(data); }

综上所述:

1、ajax和jsonp本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签调用服务器提供的js脚本并执行。

2、ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也可以做同域的数据的获取

3、没有关于 JSONP 调用错误处理。如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。例如,不能从服务器捕捉到 404 错误,也不能 取消或重新开始请求。不过,等待一段时间还没有响应的话,就不用理它了。(未来的 jQuery 版本可能有终止 JSONP 请求的特性)。

4、JSONP 的另一个主要缺陷是被不信任的服务使用时会很危险。因为 JSONP 服务返回打包在函数调用中的 JSON 响应,而函数调用是由浏览器执行的,这使宿主 Web 应用程序更容易受到各类攻击。如果打算使用 JSONP 服务,了解它能造成的威胁非常重要。



注:还有一个问题,ajax跨域上传文件 这个还没有研究好。不过有个想法用一个Nginx作转发看看行不行。再见



一些资料参考自: JSONP详解
原文链接:https://www.f2er.com/ajax/162155.html

猜你在找的Ajax相关文章