两个WSGI服务器在不同端口上本地运行.一台服务器返回一个包含javascript的html页面,该页面使用jQuery对另一个WSGI服务器执行跨源ajax请求.
origin_server.py在http:// localhost:9010提供html.
#!/usr/bin/env python from wsgiref.simple_server import make_server def origin_html(environ,start_response): status = '200 OK' response_headers = [('Content-Type','text/html')] start_response(status,response_headers) f = open('./index.html','rb') return [f.read()] httpd = make_server('localhost',9010,origin_html) httpd.serve_forever()
cors_server.py提供javascript将请求的跨源资源.
#!/usr/bin/env python from wsgiref.simple_server import make_server import json def cors_json(environ,start_response): status = '200 OK' response_headers = [ ('Content-Type','application/json'),('Access-Control-Allow-Origin','*') ] start_response(status,response_headers) return [json.dumps({'foo': 'bar'})] httpd = make_server('localhost',9011,cors_json) httpd.serve_forever()
index.html由origin_sever.py提供的页面.
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js" > </script> <script type="text/javascript"> $(document).ready(function () { console.log('Doing the thing.'); $.get('http://localhost:9011').done(function (data) { console.log('Got the thing',data); }); }); </script> </head> <body> Beep boop. </body> </html>
github上面的代码在这里:https://github.com/thatjpk/local-wsgi-cors-ajax
供参考的东西版本:
> 2012年中期MacBook Pro,OS X 10.10
> Python 2.7.6
> wsgiref 0.1.2
> Chrome 40.0.2214.93(已禁用扩展程序并重置设置以进行测试.)
> Firefox 35.0.1
问题
鉴于上述情况,我可以打开两个终端,在一个中启动origin_server.py,在另一个中启动cors_server.py,然后打开浏览器选项卡并将其指向http:// localhost:9010 /的源服务器.这会加载页面,并执行跨源请求.
理想情况下,延迟应该都非常低,因为它都是本地的.但是,我一直看到超过十秒的跨源请求的延迟.什么是bizzarre我只是在Chrome中的非隐身窗口中看过这个.同一台计算机上的Firefox,curl,httpie和Chrome隐身标签都可以在10毫秒内完成跨源请求,而非隐身Chrome标签则需要三个数量级.
如果我将CORS排除在等式之外,只需将http:// localhost:9011放入Chrome地址栏,json就会立即加载到视图中.这显然只有在请求来自javascript时才会发生.
如果在Chrome中对它的请求为“待处理”时尝试向cors_server.py发出另一个请求,则第二个请求将等到第一个请求完成时.这意味着在执行到达cors_server.py中的处理程序之前,第一个请求以某种方式将wsgi服务器占用了很长时间.
当请求永远完成时,肯定会有更多的事情发生.我使用tcpdump -i lo0 dst端口9011或src端口9011收集了以下内容.
这是来自httpie(http get localhost:9011)的请求,可以快速完成.
17:33:57.176028 IP localhost.64723 > localhost.9011: Flags [S],seq 2244357563,win 65535,options [mss 16344,nop,wscale 5,TS val 910553864 ecr 0,sackOK,eol],length 0 17:33:57.176089 IP localhost.9011 > localhost.64723: Flags [S.],seq 1494086712,ack 2244357564,TS val 910553864 ecr 910553864,length 0 17:33:57.176103 IP localhost.64723 > localhost.9011: Flags [.],ack 1,win 12759,options [nop,TS val 910553864 ecr 910553864],length 0 17:33:57.176113 IP localhost.9011 > localhost.64723: Flags [.],length 0 17:33:57.176145 IP localhost.64723 > localhost.9011: Flags [P.],seq 1:136,length 135 17:33:57.176158 IP localhost.9011 > localhost.64723: Flags [.],ack 136,win 12755,length 0 17:33:57.176760 IP localhost.9011 > localhost.64723: Flags [P.],seq 1:18,length 17 17:33:57.176781 IP localhost.64723 > localhost.9011: Flags [.],ack 18,win 12758,length 0 17:33:57.176811 IP localhost.9011 > localhost.64723: Flags [P.],seq 18:55,length 37 17:33:57.176823 IP localhost.64723 > localhost.9011: Flags [.],ack 55,win 12757,length 0 17:33:57.176834 IP localhost.9011 > localhost.64723: Flags [P.],seq 55:92,length 37 17:33:57.176844 IP localhost.64723 > localhost.9011: Flags [.],ack 92,win 12756,length 0 17:33:57.176857 IP localhost.9011 > localhost.64723: Flags [P.],seq 92:178,length 86 17:33:57.176866 IP localhost.64723 > localhost.9011: Flags [.],ack 178,win 12753,length 0 17:33:57.176878 IP localhost.9011 > localhost.64723: Flags [P.],seq 178:192,length 14 17:33:57.176886 IP localhost.64723 > localhost.9011: Flags [.],ack 192,length 0 17:33:57.176961 IP localhost.9011 > localhost.64723: Flags [F.],seq 192,TS val 910553865 ecr 910553864],length 0 17:33:57.176975 IP localhost.64723 > localhost.9011: Flags [.],ack 193,TS val 910553865 ecr 910553865],length 0 17:33:57.176980 IP localhost.9011 > localhost.64723: Flags [.],length 0 17:33:57.182034 IP localhost.64723 > localhost.9011: Flags [F.],seq 136,TS val 910553870 ecr 910553865],length 0 17:33:57.182095 IP localhost.9011 > localhost.64723: Flags [.],ack 137,TS val 910553870 ecr 910553870],length 0
这是来自Firefox的请求,可以快速完成.
18:12:57.416741 IP localhost.65089 > localhost.9011: Flags [S],seq 2202457533,TS val 912890306 ecr 0,length 0 18:12:57.416794 IP localhost.9011 > localhost.65089: Flags [S.],seq 1807873905,ack 2202457534,TS val 912890306 ecr 912890306,length 0 18:12:57.416806 IP localhost.65089 > localhost.9011: Flags [.],TS val 912890306 ecr 912890306],length 0 18:12:57.416818 IP localhost.9011 > localhost.65089: Flags [.],length 0 18:12:57.416883 IP localhost.65089 > localhost.9011: Flags [P.],seq 1:346,length 345 18:12:57.416899 IP localhost.9011 > localhost.65089: Flags [.],ack 346,win 12748,length 0 18:12:57.417478 IP localhost.9011 > localhost.65089: Flags [P.],length 17 18:12:57.417492 IP localhost.65089 > localhost.9011: Flags [.],length 0 18:12:57.417516 IP localhost.9011 > localhost.65089: Flags [P.],length 37 18:12:57.417538 IP localhost.65089 > localhost.9011: Flags [.],length 0 18:12:57.417548 IP localhost.9011 > localhost.65089: Flags [P.],length 37 18:12:57.417555 IP localhost.65089 > localhost.9011: Flags [.],length 0 18:12:57.417562 IP localhost.9011 > localhost.65089: Flags [P.],seq 92:192,length 100 18:12:57.417569 IP localhost.65089 > localhost.9011: Flags [.],length 0 18:12:57.417618 IP localhost.9011 > localhost.65089: Flags [F.],length 0 18:12:57.417629 IP localhost.65089 > localhost.9011: Flags [.],length 0 18:12:57.417634 IP localhost.9011 > localhost.65089: Flags [.],length 0 18:12:57.417638 IP localhost.65089 > localhost.9011: Flags [F.],seq 346,length 0 18:12:57.417647 IP localhost.9011 > localhost.65089: Flags [.],ack 347,length 0
17:28:10.096905 IP6 localhost.64691 > localhost.9011: Flags [S],seq 2861078667,options [mss 16324,TS val 910207638 ecr 0,length 0 17:28:10.096926 IP6 localhost.9011 > localhost.64691: Flags [R.],seq 0,ack 2861078668,win 0,length 0 17:28:10.097010 IP localhost.64692 > localhost.9011: Flags [S],seq 3615577823,length 0 17:28:10.097056 IP localhost.9011 > localhost.64692: Flags [S.],seq 3533709271,ack 3615577824,TS val 910207638 ecr 910207638,length 0 17:28:10.097066 IP localhost.64692 > localhost.9011: Flags [.],TS val 910207638 ecr 910207638],length 0 17:28:10.097075 IP localhost.9011 > localhost.64692: Flags [.],length 0 17:28:10.097274 IP localhost.64692 > localhost.9011: Flags [P.],seq 1:373,length 372 17:28:10.097293 IP localhost.9011 > localhost.64692: Flags [.],ack 373,win 12747,length 0 17:28:10.098108 IP localhost.9011 > localhost.64692: Flags [P.],TS val 910207639 ecr 910207638],length 17 17:28:10.098131 IP localhost.64692 > localhost.9011: Flags [.],TS val 910207639 ecr 910207639],length 0 17:28:10.098166 IP localhost.9011 > localhost.64692: Flags [P.],length 37 17:28:10.098184 IP localhost.64692 > localhost.9011: Flags [.],length 0 17:28:10.098212 IP localhost.9011 > localhost.64692: Flags [P.],length 37 17:28:10.098232 IP localhost.64692 > localhost.9011: Flags [.],length 0 17:28:10.098246 IP localhost.9011 > localhost.64692: Flags [P.],length 86 17:28:10.098267 IP localhost.64692 > localhost.9011: Flags [.],length 0 17:28:10.098277 IP localhost.9011 > localhost.64692: Flags [P.],length 14 17:28:10.098283 IP localhost.64692 > localhost.9011: Flags [.],length 0 17:28:10.098352 IP localhost.9011 > localhost.64692: Flags [F.],length 0 17:28:10.098369 IP localhost.64692 > localhost.9011: Flags [.],length 0 17:28:10.098380 IP localhost.9011 > localhost.64692: Flags [.],length 0 17:28:10.099183 IP localhost.64692 > localhost.9011: Flags [F.],seq 373,TS val 910207640 ecr 910207639],length 0 17:28:10.099217 IP localhost.9011 > localhost.64692: Flags [.],ack 374,TS val 910207640 ecr 910207640],length 0
这是来自常规Chrome标签的请求,耗时约为18秒.
17:28:27.147218 IP6 localhost.64699 > localhost.9011: Flags [S],seq 1481186887,TS val 910224643 ecr 0,length 0 17:28:27.147230 IP6 localhost.9011 > localhost.64699: Flags [R.],ack 1481186888,length 0 17:28:27.147277 IP6 localhost.64700 > localhost.9011: Flags [S],seq 1928824698,length 0 17:28:27.147287 IP6 localhost.9011 > localhost.64700: Flags [R.],ack 1928824699,length 0 17:28:27.147331 IP6 localhost.64701 > localhost.9011: Flags [S],seq 63463797,length 0 17:28:27.147340 IP6 localhost.9011 > localhost.64701: Flags [R.],ack 63463798,length 0 17:28:27.147578 IP localhost.64704 > localhost.9011: Flags [S],seq 2185396531,length 0 17:28:27.147602 IP localhost.64705 > localhost.9011: Flags [S],seq 2307844059,length 0 17:28:27.147617 IP localhost.9011 > localhost.64704: Flags [S.],seq 4199967470,ack 2185396532,TS val 910224643 ecr 910224643,length 0 17:28:27.147627 IP localhost.64706 > localhost.9011: Flags [S],seq 324888549,length 0 17:28:27.147638 IP localhost.9011 > localhost.64705: Flags [S.],seq 1097272416,ack 2307844060,length 0 17:28:27.147643 IP localhost.64704 > localhost.9011: Flags [.],TS val 910224643 ecr 910224643],length 0 17:28:27.147665 IP localhost.9011 > localhost.64706: Flags [S.],seq 837656804,ack 324888550,length 0 17:28:27.147669 IP localhost.64705 > localhost.9011: Flags [.],length 0 17:28:27.147675 IP localhost.9011 > localhost.64704: Flags [.],length 0 17:28:27.147681 IP localhost.64706 > localhost.9011: Flags [.],length 0 17:28:27.147686 IP localhost.9011 > localhost.64705: Flags [.],length 0 17:28:27.147691 IP localhost.9011 > localhost.64706: Flags [.],length 0 17:28:27.243730 IP6 localhost.64708 > localhost.9011: Flags [S],seq 4213763930,TS val 910224733 ecr 0,length 0 17:28:27.243748 IP6 localhost.9011 > localhost.64708: Flags [R.],ack 4213763931,length 0 17:28:27.243855 IP localhost.64709 > localhost.9011: Flags [S],seq 1721904940,length 0 17:28:27.243910 IP localhost.9011 > localhost.64709: Flags [S.],seq 2521348026,ack 1721904941,TS val 910224733 ecr 910224733,length 0 17:28:27.243925 IP localhost.64709 > localhost.9011: Flags [.],TS val 910224733 ecr 910224733],length 0 17:28:27.243934 IP localhost.9011 > localhost.64709: Flags [.],length 0 17:28:27.244093 IP localhost.64709 > localhost.9011: Flags [P.],seq 1:390,length 389 17:28:27.244108 IP localhost.9011 > localhost.64709: Flags [.],ack 390,length 0 17:28:45.693569 IP localhost.64704 > localhost.9011: Flags [F.],seq 1,TS val 910243145 ecr 910224643],length 0 17:28:45.693596 IP localhost.64705 > localhost.9011: Flags [F.],length 0 17:28:45.693605 IP localhost.64706 > localhost.9011: Flags [F.],length 0 17:28:45.693627 IP localhost.9011 > localhost.64704: Flags [.],ack 2,TS val 910243145 ecr 910243145],length 0 17:28:45.693636 IP localhost.9011 > localhost.64705: Flags [.],length 0 17:28:45.693645 IP localhost.9011 > localhost.64706: Flags [.],length 0 17:28:45.693655 IP localhost.64704 > localhost.9011: Flags [.],length 0 17:28:45.693661 IP localhost.64705 > localhost.9011: Flags [.],length 0 17:28:45.693666 IP localhost.64706 > localhost.9011: Flags [.],length 0 17:28:45.693737 IP localhost.9011 > localhost.64704: Flags [F.],length 0 17:28:45.693766 IP localhost.64704 > localhost.9011: Flags [.],length 0 17:28:45.693862 IP localhost.9011 > localhost.64705: Flags [F.],length 0 17:28:45.693909 IP localhost.64705 > localhost.9011: Flags [.],length 0 17:28:45.693935 IP localhost.9011 > localhost.64706: Flags [F.],length 0 17:28:45.693949 IP localhost.64706 > localhost.9011: Flags [.],length 0 17:28:45.694861 IP localhost.9011 > localhost.64709: Flags [P.],TS val 910243146 ecr 910224733],length 17 17:28:45.694886 IP localhost.64709 > localhost.9011: Flags [.],TS val 910243146 ecr 910243146],length 0 17:28:45.694937 IP localhost.9011 > localhost.64709: Flags [P.],length 37 17:28:45.694958 IP localhost.64709 > localhost.9011: Flags [.],length 0 17:28:45.694971 IP localhost.9011 > localhost.64709: Flags [P.],length 37 17:28:45.694982 IP localhost.64709 > localhost.9011: Flags [.],length 0 17:28:45.694997 IP localhost.9011 > localhost.64709: Flags [P.],length 86 17:28:45.695009 IP localhost.64709 > localhost.9011: Flags [.],length 0 17:28:45.695016 IP localhost.9011 > localhost.64709: Flags [P.],length 14 17:28:45.695020 IP localhost.64709 > localhost.9011: Flags [.],length 0 17:28:45.695087 IP localhost.9011 > localhost.64709: Flags [F.],length 0 17:28:45.695111 IP localhost.64709 > localhost.9011: Flags [.],length 0 17:28:45.695120 IP localhost.9011 > localhost.64709: Flags [.],length 0 17:28:45.696046 IP localhost.64709 > localhost.9011: Flags [F.],seq 390,TS val 910243147 ecr 910243146],length 0 17:28:45.696069 IP localhost.9011 > localhost.64709: Flags [.],ack 391,TS val 910243147 ecr 910243147],length 0
看起来Chrome首先尝试IPv6,而wsgiref不喜欢.所以连接重置服务器发送有意义.
对于非隐身Chrome浏览器,似乎客户端会进行多次连接尝试.服务器重置前几次尝试,然后接受一些,然后只使用其中一个连接,客户端实际发送请求.我假设因为wsgiref.simple_server是单线程的,所以之前的连接必须超时才能使得实际请求得到处理;因此延迟.
有趣的是,即使隐身Chrome仍然会重置,但只有它只重试一次,然后按预期工作. Firefox和httpie都只建立一个运行顺畅的单一连接.
问题
>为什么Chrome会尝试为单个请求打开这么多连接?
> Chrome的隐身模式会让它表现得更加愉快,在这里?
>这是……一个错误吗? (在Chrome或wsgiref中?)
解决方法
事实证明这是因为Chrome的“优化”可以加快页面加载,API交互等.
Chrome有一个名为“预测网络操作以提高网页加载效果”的设置. (在高级设置中它处于隐私状态.)启用此选项后,即使在客户端代码到达执行点之前,Chrome也会抢先打开与主机上资源的服务器的TCP连接,这将告诉浏览器发出HTTP请求.
在这种情况下,Chrome发现我将向CORS服务器发出一个AJAX请求,并打开多个与服务器的TCP连接,以便为我稍后可能提出的其他HTTP请求做准备(即使我的javascript只会发出一个请求)到服务器).它显然在连接之前打开这些额外的连接,实际上将携带javascript将发出的一个HTTP请求.这意味着对于单线程服务器,这些附加连接必须超时才能提供将承载请求的连接.这是延迟的来源.
默认情况下启用“预测网络操作以提高页面加载性能”设置,并且在隐身时处于非活动状态(可能是因为它将用户的行为泄露给可能或可能实际上不会获得请求的服务器).在此方案中,禁用它可防止打开这些额外连接,Chrome的行为与Firefox完全相同.
这让我想知道Chrome在互联网上的生产服务器上打开了多少TCP连接,这些连接要么在使用之前未使用,要么在发送请求之前保持打开一段时间.未使用的连接甚至不会显示在访问日志中,因为没有发出HTTP请求,因此很难估计Chrome用户创建了多少额外负载.在我看来,这种行为是有害的.首先,因为它试图提高客户端性能(这是令人钦佩的),但这样做是以服务器操作符为代价的(不是).第二,因为(因为它被隐姓埋名而被忽视)具有负面的隐私含义.