这几天做一个服务,主要是提供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详解

Ajax跨域和JSONP的更多相关文章

  1. ios – 尝试向我们分配IP而不是localhost或home时,NSURLSession失败

    我有一台本地运行的服务器(我的IP是192.168.0.98),并且已经尝试使用一些网络代码来访问它.最初这是通过AFNetworking完成的,但我现在用这样的NSURLSession完成了它:然后我用这3个URL运行它:>http://localhost:8080/api–>作品.>http://127.0.0.1:8080/api–>作品.>http://192.168.0.98:8080/

  2. iOS 10.3:模拟器HTTPS localhost:SSL错误

    这适用于iOS10.2及更低版本,但升级到10.3后,当模拟器尝试通过HTTPS连接到运行在localhost上的开发服务器时,Xcode控制台会输出以下错误:打印出URLSessionDataTask返回的错误显示:参考:Apple:Developer:GuidesandSampleCode:TechnicalNoteTN2232:HTTPSServerTrustEvaluation要创建自签名

  3. 应用程序关闭时的iOS任务

    我正在构建一个应用程序,通过ajax将文件上传到服务器.问题是用户很可能有时不会有互联网连接,并且客户希望在用户重新连接时安排ajax调用.这可能是用户在离线时安排文件上传并关闭应用程序.应用程序关闭时可以进行ajax调用吗?

  4. KeyStone安装部署笔记

    KeyStone客户端:OpenStack身份服务API的命令行接口。OpenStack出于扩展性的考虑也支持多个region。下面的命令在regionOne创建了keystone的三种端点:为admin租户和用户申请令牌:最后验证admin租户和用户:输出结果验证了身份服务工作正常,Keystone安装部署成功。

  5. 如何将android客户端连接到我的笔记本电脑内的Apache服务器(php)的localhost?

    我的笔记本电脑中的localhost-127.0.0.1或android10.0.0.1中的localhost?>那么,如果我想从android访问localhost来调用PHP来运行?哪个ip地址/url我需要放在Android应用程序?我需要在httpconfig中为XAMPP修改任何内容吗?解决方法使用ipconfig在笔记本电脑中找到您的IP地址.在手机中使用该地址而不是127.0.0.1.

  6. android – Phonegap本地构建 – jquery ajax错误:readystate 0 responsetext status 0 statustext error

    解决方法您是否在索引文件中包含了内容安全元标记?

  7. 尝试从Android模拟器连接到我的REST服务器时连接被拒绝

    考虑以下android代码,请解决我的问题:在我的笔记本电脑上运行REST服务器..我可以从我的浏览器访问该服务器并获得正确的结果…在模拟器中,当我将URL传递为http://www.google.com时,我得到了正确的结果,但是当我使用我的localhosturl时,我得到连接拒绝…

  8. android – 为什么我的StringRequest永远在onErrorResponse方法?

    我正在尝试从Android中执行POST请求,以在PHPmyadmin中插入一些信息.我在用什么>Slim使连接和查询与数据库存储在PHPmyadmin.>XAMPP来模拟本地服务器.>Volley来消费Android的请求.Slimpost功能对我来说没有任何问题,因为如果我在Postman应用程序上使用POST模式,数据正被插入到数据库中.该URL可以接受两个由斜杠/分隔的参数.这里有一个例子

  9. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  10. Ajax简单的异步交互及Ajax原生编写

    一提到异步交互大家就会说ajax,仿佛ajax这个技术已经成为了异步交互的代名词.那下面将研究ajax的核心对象

随机推荐

  1. xe-ajax-mock 前端虚拟服务

    最新版本见Github,点击查看历史版本基于XEAjax扩展的Mock虚拟服务插件;对于前后端分离的开发模式,ajax+mock使前端不再依赖后端接口开发效率更高。CDN使用script方式安装,XEAjaxMock会定义为全局变量生产环境请使用xe-ajax-mock.min.js,更小的压缩版本,可以带来更快的速度体验。

  2. vue 使用 xe-ajax

    安装完成后自动挂载在vue实例this.$ajaxCDN安装使用script方式安装,VXEAjax会定义为全局变量生产环境请使用vxe-ajax.min.js,更小的压缩版本,可以带来更快的速度体验。cdnjs获取最新版本点击浏览已发布的所有npm包源码unpkg获取最新版本点击浏览已发布的所有npm包源码AMD安装require.js安装示例ES6Module安装通过Vue.use()来全局安装示例./Home.vue

  3. AJAX POST数据中文乱码解决

    前端使用encodeURI进行编码后台java.net.URLDecoder进行解码编解码工具

  4. Koa2框架利用CORS完成跨域ajax请求

    实现跨域ajax请求的方式有很多,其中一个是利用CORS,而这个方法关键是在服务器端进行配置。本文仅对能够完成正常跨域ajax响应的,最基本的配置进行说明。这样OPTIONS请求就能够通过了。至此为止,相当于仅仅完成了预检,还没发送真正的请求呢。

  5. form提交时,ajax上传文件并更新到&lt;input&gt;中的value字段

  6. ajax的cache作用

    filePath="+escape;},error:{alert;}});解决方案:1.加cache:false2.url加随机数正常代码:网上高人解读:cache的作用就是第一次请求完毕之后,如果再次去请求,可以直接从缓存里面读取而不是再到服务器端读取。

  7. 浅谈ajax上传文件属性contentType = false

    默认值为contentType="application/x-www-form-urlencoded".在默认情况下,内容编码类型满足大多数情况。在这里,我们主要谈谈contentType=false.在使用ajax上传文件时:在其中先封装了一个formData对象,然后使用post方法将文件传给服务器。说到这,我们发现在JQueryajax()方法中我们使contentType=false,这不是冲突了吗?这就是因为当我们在form标签中设置了enctype=“multipart/form-data”,

  8. 909422229_ajaxFileUpload上传文件

    ajaxFileUpload.js很多同名的,因为做出来一个很容易。我上github搜AjaxFileUpload出来很多类似js。ajaxFileUpload是一个异步上传文件的jQuery插件传一个不知道什么版本的上来,以后不用到处找了。语法:$.ajaxFileUploadoptions参数说明:1、url上传处理程序地址。2,fileElementId需要上传的文件域的ID,即的ID。3,secureuri是否启用安全提交,默认为false。4,dataType服务器返回的数据类型。6,error

  9. AJAX-Cache:一款好用的Ajax缓存插件

    原文链接AJAX-Cache是什么Ajax是前端开发必不可少的数据获取手段,在频繁的异步请求业务中,我们往往需要利用“缓存”提升界面响应速度,减少网络资源占用。AJAX-Cache是一款jQuery缓存插件,可以为$.ajax()方法扩展缓存功能。

  10. jsf – Ajax update/render在已渲染属性的组件上不起作用

    我试图ajax更新一个有条件渲染的组件。我可以确保#{user}实际上是可用的。这是怎么引起的,我该如何解决呢?必须始终在ajax可以重新呈现之前呈现组件。Ajax正在使用JavaScriptdocument.getElementById()来查找需要更新的组件。但是如果JSF没有将组件放在第一位,那么JavaScript找不到要更新的内容。解决方案是简单地引用总是渲染的父组件。

返回
顶部