jquery ajax header$ajax发送请求时候为什么会报拒绝设置不安全的header

怎样防止重复发送 Ajax 请求?
一个简易的需求,点一个按钮,则向服务器请求资源,不作处理时,多次点击后会有很多个请求在等待。粗暴的解决方式是点一次就将按钮disable掉。请问一下有没有更好的办法,比如多点一次后自动down掉前一次请求?补充:不是一次请求,更类似于gmail的全站AJAX,刚用firebug看了一下gmail,发现重复请求时,之前的请求状态变为“Aborted”,并且不反回任何数据。请问是如何做到的呢?毕竟一般理解客户端AJAX发送后是不能终止的。
不推荐用外部变量锁定或修改按钮状态的方式,因为那样比较难:要考虑并理解 success, complete, error, timeout 这些事件的区别,并注册正确的事件,一旦失误,功能将不再可用;不可避免地比普通流程要要多注册一个 complete 事件;恢复状态的代码很容易和不相干的代码混合在一起;我推荐用主动查询状态的方式(A、B,jQuery 为例)或工具函数的方式(C、D)来去除重复操作,并提供一些例子作为参考:A. 独占型提交只允许同时存在一次提交操作,并且直到本次提交完成才能进行下一次提交。module.submit = function() {
if (this.promise_.state() === 'pending') {
return this.promise_ = $.post('/api/save')
B. 贪婪型提交无限制的提交,但是以最后一次操作为准;亦即需要尽快给出最后一次操作的反馈,而前面的操作结果并不重要。module.submit = function() {
if (this.promise_.state() === 'pending') {
this.promise_.abort()
比如某些应用的条目中,有一些进行类似「喜欢」或「不喜欢」操作的二态按钮。如果按下后不立即给出反馈,用户的目光焦点就可能在那个按钮上停顿许久;如果按下时即时切换按钮的状态,再在程序上用 abort 来实现积极的提交,这样既能提高用户体验,还能降低服务器压力,皆大欢喜。C. 节制型提交无论提交如何频繁,任意两次有效提交的间隔时间必定会大于或等于某一时间间隔;即以一定频率提交。module.submit = throttle(150, function() {
如果客户发送每隔100毫秒发送过来10次请求,此模块将只接收其中6个(每个在时间线上距离为150毫秒)进行处理。这也是解决查询冲突的一种可选手段,比如以知乎草稿举例,仔细观察可以发现:编辑器的 blur 事件会立即触发保存;保存按钮的 click 事件也会立即触发保存;但是存在一种情况会使这两个事件在数毫秒内连续发生——当焦点在编辑器内部,并且直接去点击保存按钮——这时用 throttle 来处理是可行的。另外还有一些事件处理会很频繁地使用 throttle,如: resize、scroll、mousemove。D. 懒惰型提交任意两次提交的间隔时间,必须大于一个指定时间,才会促成有效提交;即不给休息不干活。module.submit = debounce(150, function() {
还是以知乎草稿举例,当在编辑器内按下 ctrl + s 时,可以手动保存草稿;如果你连按,程序会表示不理解为什么你要连按,只有等你放弃连按,它才会继续。============更多记忆中的例子方式 C 和 方式 D 有时更加通用,比如这些情况:游戏中你捡到一把威力强大的高速武器,为了防止你的子弹在屏幕上打成一条直线,可以 throttle 来控制频率;在弹幕型游戏里,为了防止你把射击键夹住来进行无脑游戏,可以用 debounce 来控制频率;在编译任务里,守护进程监视了某一文件夹里所有的文件(如任一文件的改变都可以触发重新编译,一次执行就需要2秒),但某种操作能够瞬间造成大量文件改变(如 git checkout),这时一个简单的 debounce 可以使编译任务只执行一次。而方式 C 甚至可以和方式 B 组合使用,比如自动完成组件(Google 首页的搜索就是):当用户快速输入文本时(特别是打字能手),可以 throttle
keypress 事件处理函数,以指定时间间隔来提取文本域的值,然后立即进行新的查询;当新的查询需要发送,但上一个查询还没返回结果时,可以 abort 未完成的查询,并立即发送新查询;----- update
-----E. 记忆型var scrape = memoize(function(url) {
return $.post('/scraper', { 'url': url })
对于同样的参数,其返回始终结果是恒等的——每次都将返回同一对象。应用例子有编辑器,如粘贴内容时抓取其中的链接信息,memoize 用以保证同样的链接不会抓取两次。----- update
-----F. 累积型前几天处理自动完成事件时得到这个函数,发现也可以用在处理连续事件上,它能够把连续的多次提交合并为一个提交,比如:var request = makePile(5, function() {
$.post('/', { list: JSON.stringify([].slice.call(arguments)) })
// 连续发送五次
request({a:1}), request({a:2}), request({a:3}), request({a:4}), request({a:5})
/* post =&
list:[{"a":1},{"a":2},{"a":3},{"a":4},{"a":5}]
样例实现:var makePile = function(count, onfilter, onvalue) {
var values = [], id = function(value) { return value }
return function(value) {
values.push((onvalue || id).apply(this, arguments))
if (values.length === count) {
onfilter.apply(this, values)
values = []
----- update
-----另一种累积是按时间而不是次数,比如应用在行为统计上,可能在瞬间收集到数十上百类似的行为,这时可以用上面 pile 的结构加上 debounce 来防止大批重复请求(但又不丢失任何统计):var trackFactory = function(delay, action) {
var params = [], slice = [].slice
var touch = debounce(delay, function() {
if (params.length) {
action(params)
params = []
return function() {
params.push(slice.call(arguments))
var track = trackFactory(550, function(params) {
// send tracking request
G. 采样型这是最近重构时联想到的,一种和上面都不同的去重操作,可以应用在自动加载(timeline)行为控制上:autoload.listen(feeds, 'next', sample(3, function() {
this.enable()
如果 sample 是固化的选择函数(n 选 1),它这实际上会这样工作:O-O-X-O-O-X
但「自动加载」的应用可能想要的是(两次自动,一次手动):X-X-O-X-X-O
对于这种情况,可以定义作为配置的选择函数来实现控制:options { sample: (n) =& n % 3 !== 0 }
即每个下一次加载完成之后, 每三次有两次对下一次加载实行自动加载。
disabled掉按钮是常态吧?难道交互不该如此么?随便比较麻烦。最好的交互是点一下,按钮disabled,然后显示正在提交。提交失败后再恢复,成功后直接提交掉。
通常需要防止重复Ajax请求的情形:表单提交这种情形在表单submit按钮点击后,一般采取disable按钮,防止重复点击,也就防止了重复请求。不过你需要处理各种出错情形,然后enable按钮,以便用户修改数据再次提交。资源请求比如有四个Tab标签,点击每个标签都将从服务端获取数据。如果用户快速点击标签,那么将不可避免的产生重复。可以像@马骁 所说的,设定flag。如果上一个请求尚未处理完毕,就不发送新的请求。但这么处理一是不够通用,二是用户体验也不好,因为用户希望点击Tab就立刻得到响应。因此,通常做法是abort掉上一个请求。用于Ajax请求的XMLHttpRequest对象有abort方法,直接调用就好了。
我的经验的做法是,封装自己的Ajax请求对象.不使用直接使用系统的或者其他第三方的包装.有了自己的封装之后,并不是简单abort就是最好的.我这里会根据实际的情况做处理:1. 所有的Ajax请求都是异步的,我的封装中做一个100毫秒的setTimeout延时.这样就可以有效的解决用户快速重复点击的问题. 足够快的时候,前一请求并没有真正的发出来.就被clearTimeout清除掉了. abort掉Ajax的请求也会有服务端响应,需要消耗资源.2.如果用户的操作不并足够快.比如点了保存按钮,在服务器没有返回成功的时候,再次点了保存按钮.(事实上两次请求是一样的.而我们更希望第一次的请求是有效的,第二次的可以不做处理).在封装中,我们检查传入ajax的请url及参数是否一致,如果一致.则第二次的AJAX并不发出.3.最后一种情况,两次相间的请求是不同的请求,比如楼上说快速切换Tab的例子.无法,只能abort掉前一个Ajax请求了.再补充一点,统一的Ajax封装有许多特别的好处:1.可以计数pending中的请求数,显示当前还有几个请求进行中(我们原来的系统中有一个这样的需求,一般系统也会有比如显示loading的需求...)2.可以有统一的异常处理,发送的请求失败了(服务器可以返回统一的格式,客户端做集中处理,弹出错框等,或者如firebug那样,把所有的异常放到一个统一的地方去.或者调试阶段增加处理.)3.如果有大量的小请求,比如取某个表单的下拉列表.一堆下拉框的话.可以在客户端做请求合并.batching Ajax, 这个是从DWR中获得的灵感.
如果用jquery的话,jquery的ajax提供ajaxPrefilter方法对ajax请求进行拦截,可以在公用的js里配置上1个公用的ajaxPrefilter。全局维护1个request的列表,在ajaxPrefilter中判断要发送的请求是否已经存在,如不存在则发送并将发送中的请求存储到本地,同时覆盖掉传进来的options下的complete属性,在里面包裹上请求完成后踢出队列的处理。其它框架的话用类似的方式处理,基本思想就是对原始提供的全局ajax方法进行简单包装下即可。// 所有ajax请求的通用前置filter
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
// 不重复发送相同请求
var key = generatePendingRequestKey(options);
if (!pendingRequests[key]) {
storePendingRequest(key, jqXHR);
// or do other
jqXHR.abort();
var complete = options.complete;
options.complete = function(jqXHR, textStatus) {
// clear from pending requests
pendingRequests[jqXHR.pendingRequestKey] = null;
if ($.isFunction(complete)) {
complete.apply(this, arguments);
以上是sample code。几个地方都可以定制:如何算同1个请求遇到发送相同请求的具体处理,可以选择abort之前的,也可以直接abort掉后发的,完全取决于业务需求
如果是GET请求。可以利用http的缓存机制,如果是post请求,可以增加token,服务器只接受第一次请求的token
我常用的方式1. setTimeout + clearTimeout连续的点击会把上一次点击清除掉,也就是ajax请求会在最后一次点击后发出去2. disable 按钮3. 每次点击都发请求,往回调里加闭包带唯一递增的id,每一次请求回调以后看这个id是不是主函数体里最后一次点击的id,是则调用回调,不是则返回,也就是ajax回数后看这个回调是不是最后一次点击的回调,不是就不操作页面了第1,2种请求是做用户疯狂快速点击时防止发大量请求的第3种是用户不那么频繁的点击,但是每一次点击ajax请求回数时间比较长,也就是第二次请求可能比第一次先回数这种特殊情况的
最早我看到这个问题的时候,我也在苦恼这个问题,我也没有系统的解决办法。所以解决办法是,每次都在提交的btn 上加一个状态,然后检查这个状态。====================后来随着我的经验增加,也看了一些优秀的源码。现在我用的方式是,用一个全局的管理“操作”的管理器来管理这些操作。简单实现:var ActionManager = {};
var actionName = url //提交的地址
if(ActionManager[actionName])
ActionManager[actionName]
= function(){};//某个操作的具体执行函数
ActionManager[actionName].call(this);
以上是超简略实现。丰富起来,可以给 ActionManager 增加方法如addActionexcuteAction并对这些方法增加参数,表示是否需要阻塞;增加回调如执行前回调、执行后回调、如果遇到阻塞时的回调。这样可以实现对界面很多的操作或者功能阻塞检查,防止重复操作。不仅仅是ajax的重复提交。
$q执行时候可以传一个cancel方法进去,一旦这个方法返回值变为true的时候就会取消这个请求不过这个取消仅限客户端,服务器端还是会被茫茫多的请求轰炸所以就必须限制流量我用过两个方法客户端有一个全局检查(或者是某种方式的检查),在一个请求出现后延迟0.2秒(时间可以改动)再发往服务器端。如果在此期间发生新的请求,直接取消前一个请求并重置0.2秒的等待。这招对于监测鼠标滚轮事件有奇效服务器端如果你有心的话可以计算一个request token,然后执行前先去log里检查这个request是不是已经被执行了。不过这招远没有前边那条好implement就是了。
这是我在zepto下的实现。供你参考。 参考自
谢思路。$.ajaxSettings.beforeSend = function(xhr,options){
//当ajax快速提交时,url /platform/investor/info?CUSTOMER_ID=9A28E64C&investorId=32&_=5
// 最后一位 是 ajax自动加的时间戳。
// 需要 正则表达式
判断时间戳 然后 去掉&_=时间戳 这样的形式。
var key = options.url,
complete = plete,//暂存options的complete方法指针
flag = options.abortOnRetry !== undefined ? !!options.abortOnRetry :
//abortOnretry 属性 判定是否需要拦截重复ajax。
if(/.+&_=[\d]{13}$/.test(key)){
key = key.split('&_=')[0];
if( !flag ){
console.log('放行');
if( pendingRequests[key] !== undefined) {
console.log('阻断');
//xhr.abort();
pendingRequests[key] =
// 放弃后触发的重复提交
//pendingRequests[key].abort(); // 放弃先触发的提交
var timer = setTimeout(function(){
console.dir(pendingRequests);
pendingRequests = {};
//这个计时器,用来清空序列,5s后可以发送请求。
plete = function(xhr, Status) {//complete方法的默认形参
//重写complete方法
console.log('complete');
pendingRequests[key] =
if ($.isFunction(complete)) {
complete.apply(this, arguments);//在options下执行。
console.log('放行');
已有帐号?
无法登录?
社交帐号登录2014年5月 Web 开发大版内专家分月排行榜第二2014年4月 Web 开发大版内专家分月排行榜第二
2014年3月 Web 开发大版内专家分月排行榜第三2014年2月 Web 开发大版内专家分月排行榜第三2013年7月 .NET技术大版内专家分月排行榜第三2013年6月 .NET技术大版内专家分月排行榜第三2012年9月 .NET技术大版内专家分月排行榜第三
2014年5月 Web 开发大版内专家分月排行榜第二2014年4月 Web 开发大版内专家分月排行榜第二
2014年3月 Web 开发大版内专家分月排行榜第三2014年2月 Web 开发大版内专家分月排行榜第三2013年7月 .NET技术大版内专家分月排行榜第三2013年6月 .NET技术大版内专家分月排行榜第三2012年9月 .NET技术大版内专家分月排行榜第三
2016年10月 .NET技术大版内专家分月排行榜第一2016年8月 .NET技术大版内专家分月排行榜第一2016年7月 .NET技术大版内专家分月排行榜第一
2016年9月 .NET技术大版内专家分月排行榜第二2016年6月 .NET技术大版内专家分月排行榜第二2016年3月 .NET技术大版内专家分月排行榜第二2016年1月 .NET技术大版内专家分月排行榜第二2015年12月 .NET技术大版内专家分月排行榜第二2015年2月 .NET技术大版内专家分月排行榜第二2015年1月 .NET技术大版内专家分月排行榜第二2014年11月 .NET技术大版内专家分月排行榜第二2014年5月 .NET技术大版内专家分月排行榜第二2014年4月 .NET技术大版内专家分月排行榜第二2012年2月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第二
2016年10月 .NET技术大版内专家分月排行榜第一2016年8月 .NET技术大版内专家分月排行榜第一2016年7月 .NET技术大版内专家分月排行榜第一
2016年9月 .NET技术大版内专家分月排行榜第二2016年6月 .NET技术大版内专家分月排行榜第二2016年3月 .NET技术大版内专家分月排行榜第二2016年1月 .NET技术大版内专家分月排行榜第二2015年12月 .NET技术大版内专家分月排行榜第二2015年2月 .NET技术大版内专家分月排行榜第二2015年1月 .NET技术大版内专家分月排行榜第二2014年11月 .NET技术大版内专家分月排行榜第二2014年5月 .NET技术大版内专家分月排行榜第二2014年4月 .NET技术大版内专家分月排行榜第二2012年2月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第二
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。2016年2月 总版技术专家分月排行榜第二2014年2月 总版技术专家分月排行榜第二2013年4月 总版技术专家分月排行榜第二
2016年8月优秀小版主2016年7月优秀小版主优秀小版主2015年7月优秀小版主2015年9月优秀小版主2015年5月优秀小版主2014年11月论坛优秀版主
2016年2月 总版技术专家分月排行榜第二2014年2月 总版技术专家分月排行榜第二2013年4月 总版技术专家分月排行榜第二
2016年8月优秀小版主2016年7月优秀小版主优秀小版主2015年7月优秀小版主2015年9月优秀小版主2015年5月优秀小版主2014年11月论坛优秀版主
2016年2月 总版技术专家分月排行榜第二2014年2月 总版技术专家分月排行榜第二2013年4月 总版技术专家分月排行榜第二
2016年8月优秀小版主2016年7月优秀小版主优秀小版主2015年7月优秀小版主2015年9月优秀小版主2015年5月优秀小版主2014年11月论坛优秀版主
本帖子已过去太久远了,不再提供回复功能。jQuery$.ajax发送请求时候为什么会报拒绝设置不安全的header?
function testpost(){
url:loginUrl,
type: 'POST',
headers : {
Cookie:Cookieid,
success: function(data){
alert(data);
我设置Cookie提交后..会报 Refused to set unsafe header "cookie"
因为用 xhr 无法设置 cookie 字段。var xhr = new XMLHttpRequest();
xhr.open('GET','/',true);
xhr.setRequestHeader('cookie','1');
// Error: Refused to set unsafe header "cookie"
浏览器不允许用户手动设置敏感的Http header包括但不限于cookiehostreferer
为了安全,跨域XHR对象有一些限制:不能使用 setRequestHeader() 设置自定义头部不能发送和接收 cookie调用 getAllResponseHeaders() 方法总会返回空字符串参考:1.《JavaScript高级程序设计(第3版)》 - 21.4.2 其他浏览器对 CORS 的实现
已有帐号?
无法登录?
社交帐号登录温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
参考代码:// attempt to make an XMLHttpRequest
// jQuery 1.6.1
and Chrome
dev 13.0.767
function makeRequest() {
alert("inside makeRequest()");
var settings = {
type: "GET",
url:URL+"?"+REQUEST,
dataType:"xml",
error: function(XHR,textStatus,errorThrown) {
alert ("XHR="+XHR+"\ntextStatus="+textStatus+"\nerrorThrown=" + errorThrown);
success: function(data,textStatus) {
$("body").append(data);
headers: {
"Access-Control-Allow-Origin":"http://example.edu",
"Access-Control-Allow-Headers":"X-Requested-With"
$.ajax(settings);
阅读(18750)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'jquery ajax请求时,设置请求头信息',
blogAbstract:'设置一个名为 headers 的参数参考代码:// attempt to make an XMLHttpRequest \n// jQuery 1.6.1
and Chrome
dev 13.0.767\nfunction makeRequest() {\n
alert(\"inside makeRequest()\");\n
var settings = {\n
type: \"GET\",\n
url:URL+\"?\"+REQUEST,\n
dataType:\"xml\",\n
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:6,
publishTime:7,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:true,
hostIntro:'',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}}

我要回帖

更多关于 jquery ajax 跨域请求 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信