我在最近的一个
web
项目中为了实现
bookmark
功能碰到了
javascript
跨域访问的问题。起初,在
google
上搜的很多凯发天生赢家一触即发官网的解决方案并不适用于我的情形,只在有一篇文章中提到的远程加载
javascript
方法从理论上看到了解决的希望。但可惜作者只是一笔带过,并未用例子详细说明,所以不得不摸索了一阵才把这个问题搞定。在此,希望通过本文为同样被这个问题困扰的朋友们提供一个解决方法作为参考。如有错误,欢迎指正!
bookmark
是目前许多
web2.0
网站
(http://del.icio.us/, www.diigo.com
等)都提供的热门
feature
。它能将互联网上自己喜欢的网页收藏到
bookmark
服务器上。本文要解决的问题就发生在用户提交网页
url
(还包括
tag, notes
等)给
bookmark
服务器时。
关于
url
的提交至少可以有三种方式:
1.
登陆
bookmark
服务器的提交页面,将要收藏的
url
通过该页面提交给服务器。
2.
安装浏览器插件,通过插件将
url
提交给服务器。
3.
从
bookmark
服务器动态加载
javascript
小工具到当前页面,通过它来完成提交工作。(参考
diigo
的例子,收藏一个网页链接到浏览器收藏夹,链接的
url
是一段
javascript
代码,它会从服务器加载一段
javascript
注入当前网页)
第一种方式开发起来最简单,但对用户来讲比较麻烦,每次都需要先登陆
bookmark
服务器才能完成提交;第二种方式我并不熟悉插件开发,而且用户也不喜欢太多的插件堆满自己的浏览器;第三种方式开发难度小,又避免了每次登陆服务器的麻烦,所以我最终采用了它。
上面讲的第三种方式中动态加载的
javascript
小工具除了需要生成
ui
供用户填写信息(
url
,
tag
,
notes
等),当用户点击提交的时候,还要完成与服务器通信的功能。在没有跨域访问经验的情况下,最先想到的当然是
ajax
!但很快就会发现根本行不通。
跨域访问,简单来说就是
a
网站的
javascript
代码试图访问
b
网站,包括提交内容和获取内容。由于安全原因,跨域访问是被各大浏览器所默认禁止的。写过跨域访问
ajax
的朋友相信都遇到过被告知“没有权限”的情况。通过
xmlhttp
来发送数据给
bookmark
服务器的尝试失败了。于是,看到网上的一些资料,我又开始尝试用
javascript
小工具在用户网页动态创建一个隐藏的
iframe, iframe
的
src
指向服务器的一个
servlet
,试图通过调用
iframe
中提供的
javascript
来完成与服务器的通信。但不幸的是,用户网页中的
javascript
代码访问
iframe
也被浏览器归为跨域访问(特指
iframe
的
src
指向其它网站的情形),尝试再次失败。
最终,在一篇文章中看到,与
iframe
不同,如果
a
网站从
b
网站加载
javascript
,
a
网站可以自由的访问该
javascript
的内容,并不会被浏览器认为是跨域访问。模仿刚才
iframe
的思路,当用户点击提交时,可以动态创建一个
javascript
对象,该对象的
src
指向
bookmark
服务器的一个
servlet
,注意:
url
、
tag
、
notes
、
user
、
password
等信息被作为
src url
参数传给服务器。请看下面的代码:
var
url =
"http://localhost:8080/deeryard/bookmarkservlet?"
"url="
url_source
"&"
"title="
title
"&"
"tag="
tag
"&"
"notes="
notes
"&"
"user="
user
"&"
"password="
password;
url = encodeuri(url);
//submit to server with a trick
var
js_obj = document.createelement(
"script"
);
js_obj.type =
"text/javascript"
;
js_obj.setattribute(
"src"
, url);
//get response from server by appending it to document
document.body.appendchild(js_obj);
上面例子中,
js_obj.setarrribute()
将信息作为
src
的
url
参数提交给了
bookmark servlet
。那么用户又如何取得服务器的响应信息呢?答案就是最末一行代码,
servlet
的输出必须是
javascript
代码,它可以调用用户网页上的其他
javascript
函数,以及操作
dom
对象。下面的
servlet
代码生成了一个
javascript
函数调用:
out.write("onserverresponse(inadequate_information);");
document.body.appendchild(js_obj)
执行后
onserverresponse(
inadequate_information)
就会得到执行,使客户网页响应服务器结果。这样一个完整的通信过程就完成了。
来总结一下这个案例,首先与很多跨域访问的情形不同,本文提到的跨域访问需要对服务器端进行控制,即让服务器端
servlet
来适应客户端网页
javascript
的需求;而其他一些常见的例子则对服务器端没有控制能力,比如从其他网站抓内容的小偷程序。另外,需要注意的是这种方法中实际用到了
get
方法来提交信息,从一些资料上看到,
get
方法每次提交的信息不能超过
2k
。
2006-8-27
perl 作为一种脚本语言可以实时地生成和执行代码。这种特性可以把代码的编译推迟到运行时,所以又称为“动态代码”。另外, perl 也如 java 、 c 一样提供了异常处理机制。本文将初步探讨 perl 中实现动态代码和异常处理机制的函数: eval 。如有错误不足,欢迎讨论和批评指正。
eval 函数可以看作是 perl 虚拟机,它的参数就是一段 perl 代码。利用 ’perldoc –f eval’ 可以获取 eval 函数使用帮助,其中介绍了它的两种使用方式:
l
eval expr
expr 是一个的表达式,例如:
eval
"print $a"
;
eval
'print $a'
.
', $b'
;
eval
1
3
;
eval
'print '
.
'$a $b, "\n"'
;
eval
$command;#$command = ‘print “hello perl”’
eval
$argv[0];
在执行时, perl 解释器会首先解析表达式的值,然后将表达式值作为一条 perl 语句插入当前执行上下文。所以,新生成的语句与 eval 语句本身具有相同的上下文环境。这种方式中,每次执行 eval 语句,表达式都会被解析。所以,如果 eval expr 如果出现在循环中,表达式可能会被解析多次。 eval 的这种方式使得 perl 脚本程序能实时生成和执行代码,从而实现了“动态代码”。
l
eval block
block 是一个代码块,例如:
eval {print $a};
eval {$a = 1, $b = 2, $c = $a $b};
与第一种方式不同, block 只会被解析一次,然后整个插入当前 eval 函数所在的执行上下文。由于解析上的性能的优势,以及可以在编译时进行代码语法检查,这种方式通常被作为 perl 用来为一段代码提供异常捕捉机制,虽然前一种方式也可以。
按帮助的名称,称 eval 的参数程序为“小程序” (mini-program) 。在两种方式中, eval 函数的返回值都是小程序的最后一条语句的值,如果遇到 return 语句,与子例程相同。
script1:
#!/usr/bin/perl -w
push
(
@program,'$i = 1;');
push
(
@program,'$i = 3; $j = 2; $k = $i $j');
push
(
@program, '$i = 3; return 24; $k = $i $j');
foreach
$exp (@program)
{
$rtn =eval($exp);
print
$rtn,"\n";
}
output:
1
5
24
|
如果小程序中有语法错误、运行时错误遇到 die 语句, eval 将返回 undef 。错误码被保存在 $@ 中。
script2:
#!/usr/bin/perl -w
push
(
@program, '$i = 3; die "error message"; $k = $i $j');
foreach
$exp (@program)
{
$rtn =eval($exp);
if
(
!
defined
(
$rtn))
{
print
"exception: "
,
$@,"\n";
}
else
{
print
$rtn,"\n";
}
}
;
output:
exception: error message at (eval 1) line 1.
|
script3:
#!/usr/bin/perl -w
# a run-time error
eval
'$answer ='
;
# sets $@
warn
$@ if$@;
output:
syntax error at (eval 1) line 2, at eof
|