PHP程序员站--PHP编程开发平台
 当前位置:主页 >> 网页制作 >> Ajax >> 

Ajax跨域名解决方法

Ajax跨域名解决方法

来源:  作者:  发布时间:2007-12-27
在ajax跨域名通常情况下大家是无法去改服务器配置的
在ajax跨域名通常情况下大家是无法去改服务器配置的,只有从脚本下手了。方法很简单,用php做一个中间键,如:

PHP代码:
header("Content-Type: text/xml; charset=gb2312");
echo file_get_contents($info);

todd提供的解决方法:
设置document.domain。
前提条件:两个页面同属于一个基础域(例如都是xxx.com,或是xxx.com.cn);同一协议(例如都是http);同一端口(例如都是80)。
方法:设置两个页面的document.domain都设置为自己所在的基础域名。
例子:aaa.xxx.com里面的一个页面需要调用bbb.xxx.com里的一个对象,则将两个页面的document.domain都设置为xxx.com,就可以了。

跨浏览器、跨域的Ajax工具: Modello.ajax

问题
如果你曾经在使用 XMLHTTPRequest 的时候遇到过以下问题,那么 Modello.ajax 可以帮你解决。

XMLHTTPRequest 在各种浏览器和版本上面使用方法不一样
XMLHTTPRequest 的使用方法过于繁琐
XMLHTTPRequest 不能跨域获取资源
JavaScript 中缺乏 urlparse 、urljoin 这样的 URL 分析工具

urlget 函数
Modello.ajax 是使用 Modello 框架编写的,用于 JavaScript 联网操作的类库。它实现跨浏览器调用,跨域获取资源,并且使用起来非常简单。请看下面的例子:

// 指定 jsproxy.php 的位置
Define('URLGET_PROXY', '/jsproxy.php');

// 回调函数
var callback = function(header, body, url, chunnel) {
alert(header);
alert(body);
}

var url = 'http://www.baidu.com';
var data = '';
var chunnel = null;
var headers = [];
var urlget = Class.get('modello.ajax.Urllib').urlget;

// 异步方式
urlget(url, data, callback, chunnel, headers);

// 同步方式
// var ret = urlget(url, data, null, chunnel, headers);
// ret[0]: Response header
// ret[1]: Response body

// 如果请求失败,返回 false。
// 如果成功,异步调用返回 true,同步调用返回回复的 header 和 body内容。
上面的代码执行结果就是先 alert HTTP 的头部信息,然后 alert 百度主页的 HTML 代码。下面来解释一下 url, data, callback, chunnel, headers 这五个参数的含义:

url:字符串,资源的 URL 地址。
data:字符串,POST 数据。如果为空,则使用 GET 方法获取。
callback:函数,异步回调函数。如果为空,则等待直至结果返回。回调函数接收四个参数:header, body, url, chunnel。header 是回复的头部信息,body 是回复的体部内容,url 是当前请求的URL,chunnel 是调用时指定的命名通道。
chunnel:字符串,命名通道。如果为空,则重用或者新建已有的通道。如果指定了通道的名字,而该通道正在被其它请求使用时,函数返回 false。
headers:数组,请求头部。当要获取的资源需要某些特殊的头部的时候(例如 User-Agent 或者 Referer ),可以在这个参数中加入。

urlget 各个参数的设计是按照使用频率来排列的。在大部分情况下,url, data, callback 这三个参数已经满足要求。建议尽量使用异步方式,因为同步方式虽然是起来更方便,但是它会使浏览器挂起来,等待结果的返回。在这期间,浏览器不会响应任何事件,屏幕也不会重画,给用户很不好的感受。在使用异步方式的时候,回调函数中 url 这个输入参数可以帮助你识别当前请求到底是那个 URL,这对于用一个回调函数处理多个请求的回复的情况是很有用的。

再说说 chunnel 这个参数,如果你想在客户端发出多个异步请求,而又想这些请求按照一定的顺序一个一个执行,这时候 chunnel 发挥作用。请看下面例子:

// 向服务器发出心跳请求。
var url = '...';
var data = 'action=heartbeat';
var callback = function(){};
var chunnel = 'heartbeat';
var timer = setInterval(function() {
urlget(url, data, callback, chunnel);
}, 1000);
上面例子中,如果忽略 chunnel 参数,当第一个心跳请求的执行时间超过一秒,这时,第二个心跳请求不会等待第一个请求执行完成就会发送出去。这可能不是服务器所期望的行为,另外对网络资源来说也是一种浪费。但如果设置了 chunnel 参数,第二个心跳请求不会发出去,因为这个 chunnel 正在被第一个请求占用,urlget 函数会返回 false。

jsproxy
如果要获取的资源在本域,使用 Modello.ajax 就足够了。如果要跨域获取,还需要一个放在本域的 proxy 来配合(为什么?XMLHTTPRequest 的使用有一个安全域限制。当要获取放在其它域的资源,IE会弹出安全警告,firefox 和 opera 则会出错)。在该版本中,给出一个 php 的 proxy 实现:jsproxy.php。只要将 jsproxy.php 放到本域的服务器上,然后在调用 urlget 之前插入下面一行代码:

// 指定 jsproxy.php 的位置
Define('URLGET_PROXY', '/jsproxy.php');
下面来说明一下这个 jsproxy 的实现原理。它是一个 cgi 程序,接受两个 POST 参数:url 和 data。url 是目标资源的 URL 地址,data 是POST 数据。如果 data 为空,jsproxy使用 GET 方法获取资源,否则使用 POST 方法获取资源。jsproxy 会把获取到的回复的头部信息和体部内容全部转发给 urlget。但在转发之前,jsproxy 会进行如下处理:从回复的头部和体部查找回复的 Content-Type 和字符集。对于没有 Content-Type 的回复,jsproxy 一律返回 404 给 urlget。对于没有字符集的回复,jsproxy自动加上 DEFAULT_CHARSET(这个参数在 jsproxy.php 里面设置)。jsproxy 还会对 Content-Type 进行过滤,在 jsproxy.php 里设置 ALLOW_CONTENT_TYPE 这个参数可以达到这个目的。欢迎有兴趣的朋友编写其他语言版本的 jsproxy:)

Request 类
一般情况下,urlget 已经足够了。但如果你想做一些更细致的联网操作,可以使用或者扩展这个类:modello.ajax.Request。urlget 其实就是它的封装。modello.ajax.Request 类的 API 如下:

// 类的路径
var Request = Class.get('modello.ajax.Request');

// 创建实例
// 参数:
// url: 字符串,资源的 URL 地址
// method: 字符串,获取的方法。GET 或者 POST

// data:字符串,POST的数据
var request = new Request(url, method, data);

// 设置 URL
request.seturl(/blog/url);

// 设置方法
request.setMethod(method);

// 设置 POST 数据
request.setData(data);

// 设置异步回调函数
request.setHandler(handler);

// 设置请求头部
// 参数:
// key: 字符串,名称
// value: 字符串,值
request.setHeader(key, value);

// 加入一行头部数据
request.addHeader(header);

// 打开请求
// 参数:
// async: 布尔值,是否异步。默认为 false
request.open(async);

// 中断请求
request.abort();

// 返回当前请求的状态
// 总共有 5 种状态(字符串)
// Uninitialized: 未初始化,对象已建立,但是尚未初始化(尚未调用open方法)
// Loading: 初始化,对象已建立,尚未调用send方法
// Loaded: 发送数据,send方法已调用,但是当前的状态及http头未知
// Interactive: 数据传送中,已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误
// Complete: 完成,数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据
// 上面的解释来自 www.xmlhttp.cn
request.getState();

// 回复的状态码
request.getStatus();

// 回复状态码对应的字符串解释
request.getStatusText();

// 回复头部
request.getHeader(key);

// 所有回复头部(不包含状态行)
request.getAllHeaders();

// 原始回复头部(包含状态行)
request.getRawHeader();

// 回复体部
request.getText();

// 回复体部的 XML 形式
request.getXML();

// 重置请求(清掉所有之前设置的请求头部)
request.reset();
Connection 类
如果你只是想得到一个跨浏览器的 XMLHTTPRequest 对象,可以使用如下方法。

// 跨浏览器的 XMLHTTPRequest 对象
var conn = Class.get('modello.ajax.Connection').get();
urlparse 和 urljoin 函数
除了上面的用于联网的类,Modello.ajax 还提供两个 URL 分析函数:

// URL 分析函数
var urlparse = Class.get('modello.ajax.Urllib').urlparse;


var url = 'http://kenxu:kenxu@www.ajaxwing.com:80/index.php?s=modello#top';
var ret = urlparse(url);
// 这时候
// ret.scheme: http
// ret.user: kenxu
// ret.pass: kenxu
// ret.host: www.ajaxwing.com
// ret.port: 80
// ret.path: /index.php
// ret.query: s=modello
// ret.flagment = top

// URL 合并函数
var urljoin = Class.get('modello.ajax.Urllib').urljoin;
var ret = urljoin(base, url);
// 如果这时
// base: http://www.ajaxwing.com/images
// url: index.php
// 那么
// ret: http://www.ajaxwing.com/images/index.php


// 如果 url 改成
// url: /index.php
// 那么
// ret: http://www.ajaxwing.com/index.php
// 如果 url 改成
// url: http://www.baidu.com/index.php
// 那么
// ret: http://www.baidu.com/index.php
// 就是这个原理

// 如果 base 为空,返回 url
// 如果 url 为空,返回 base

总结
Modello.ajax.Urlget 和 Modello.ajax.Connection 都是工具类,提供静态方法,使用前不需创建它的实例;Modello.ajax.Request 是一个基础类,使用前要先创建实例。
Tags: ajax   跨域名   解决   跨域   方法   域名  
最新文章
推荐阅读
月点击排行榜
PHP程序员站 Copyright © 2007-2010,PHPERZ.COM All Rights Reserved 粤ICP备07503606号