2016-03-27 18 views
9

Mã sau gửi yêu cầu 200ms một lần và phải xử lý các phản hồi một cách không đồng bộ bất cứ khi nào chúng đến.Hành vi chặn lạ với gevent/grequests qua HTTPS

Trên HTTP, nó hoạt động như mong đợi - một yêu cầu được gửi mỗi 200ms và cuộc gọi trả lời được gọi độc lập bất cứ khi nào có phản hồi. Tuy nhiên, qua HTTPS, các yêu cầu bị trì hoãn đáng kể bất cứ khi nào một phản hồi đến (mặc dù trình xử lý phản hồi của tôi không hoạt động). Phản hồi gọi lại dường như được gọi hai lần cho mỗi yêu cầu, một lần với phản hồi có độ dài bằng không (chỉnh sửa: điều này là do chuyển hướng và dường như không liên quan đến vấn đề chặn, cảm ơn Padraic).

Điều gì có thể gây ra hành vi chặn này qua HTTPS? (www.bbc.co.uk chỉ là một ví dụ về mặt địa lý xa tôi, nhưng nó xảy ra với tất cả các máy chủ tôi đã thử nghiệm).

grequests_test.py

import time 
import sys 
import grequests 
import gevent 

def cb(res, **kwargs): 
    print("**** Response", time.time(), len(res.text)) 

for i in range(10): 
    unsent = grequests.get(sys.argv[1], hooks={'response': cb}) 
    print("Request", time.time()) 
    grequests.send(unsent, grequests.Pool(1)) 
    gevent.sleep(0.2) 
gevent.sleep(5) 

$ ipython2 grequests_test.py 'http://www.bbc.co.uk' (kết quả mong đợi)

('Request', 1459050191.499266) 
('Request', 1459050191.701466) 
('Request', 1459050191.903223) 
('Request', 1459050192.10403) 
('Request', 1459050192.305626) 
('**** Response', 1459050192.099185, 179643) 
('Request', 1459050192.506476) 
('**** Response', 1459050192.307869, 179643) 
('Request', 1459050192.707745) 
('**** Response', 1459050192.484711, 179643) 
('Request', 1459050192.909376) 
('**** Response', 1459050192.696583, 179643) 
('Request', 1459050193.110528) 
('**** Response', 1459050192.870476, 179643) 
('Request', 1459050193.311601) 
('**** Response', 1459050193.071679, 179639) 
('**** Response', 1459050193.313615, 179680) 
('**** Response', 1459050193.4959, 179643) 
('**** Response', 1459050193.687054, 179680) 
('**** Response', 1459050193.902827, 179639) 

ipython2 grequests_test.py 'https://www.bbc.co.uk' (yêu cầu được gửi cuối)

('Request', 1459050203.24336) 
('Request', 1459050203.44473) 
('**** Response', 1459050204.423302, 0) 
('Request', 1459050204.424748) <------------- THIS REQUEST TIME IS LATE 
('**** Response', 1459050205.294426, 0) 
('Request', 1459050205.296722) 
('Request', 1459050205.497924) 
('**** Response', 1459050206.456572, 0) 
('Request', 1459050206.457875) 
('**** Response', 1459050207.363188, 0) 
('**** Response', 1459050208.247189, 0) 
('Request', 1459050208.249579) 
('**** Response', 1459050208.250645, 179643) 
('**** Response', 1459050208.253638, 179643) 
('Request', 1459050208.451083) 
('**** Response', 1459050209.426556, 0) 
('Request', 1459050209.428032) 
('**** Response', 1459050209.428929, 179643) 
('**** Response', 1459050210.331425, 0) 
('**** Response', 1459050211.247793, 0) 
('Request', 1459050211.251574) 
('**** Response', 1459050211.252321, 179643) 
('**** Response', 1459050211.25519, 179680) 
('**** Response', 1459050212.397186, 0) 
('**** Response', 1459050213.299109, 0) 
('**** Response', 1459050213.588854, 179588) 
('**** Response', 1459050213.590434, 179643) 
('**** Response', 1459050213.593731, 179643) 
('**** Response', 1459050213.90507, 179643) 
('**** Response', 1459050213.909386, 179643) 

Lưu ý rằng phản hồi đầu tiên dường như đến lâu sau khi yêu cầu tiếp theo nên đã được gửi nhưng không. Tại sao giấc ngủ không quay lại, và yêu cầu tiếp theo được gửi đi, trước khi câu trả lời đầu tiên đến?

Trả lời

1

Các lặp hiện tại của grequests chứa sau:

from gevent import monkey as curious_george 
curious_george.patch_all(thread=False, select=False) 

Phần vi phạm là select=False - loại bỏ này hoặc bằng tay gọi monkey.patch_select() giải quyết vấn đề. Tôi không chắc chắn nếu điều này có tác dụng phụ khác.

1

Các phản ứng phụ và 0 responses chiều dài được giải thích một cách dễ dàng, nếu bạn thêm một print(res.status_code) bạn sẽ thấy rất nhiều của 301 như trong trường hợp của https://www.bbc.co.uk bạn được chuyển đến http://www.bbc.co.uk vì vậy đó là lý do tại sao bạn thấy tính năng bổ sung câu trả lời và 0 trở cho len(res.text), bạn sẽ nhìn thấy đầu ra dưới đây:

In [11]: def cb(res, **kwargs): 
    ....:   print(res.status_code) 
    ....:   print("**** Response", time.time(), len(res.text)) 
    ....:  

In [12]: for i in range(10): 
    ....:   unsent = grequests.get("https://www.bbc.co.uk", hooks={'response': cb}) 
    ....:   print("Request", time.time()) 
    ....:   grequests.send(unsent, grequests.Pool(1)) 
    ....:   gevent.sleep(0.2) 
    ....: gevent.sleep(5) 
    ....: 
('Request', 1459368704.32843) 
301 
('**** Response', 1459368704.616453, 0) 
('Request', 1459368704.618786) 
301 
('**** Response', 1459368704.937159, 0) 
('Request', 1459368704.941069) 
200 
('**** Response', 1459368704.943034, 141486) 
301 
('**** Response', 1459368705.496423, 0) 
('Request', 1459368705.498991) 
200 
('**** Response', 1459368705.50162, 141448) 
301 
('**** Response', 1459368705.784145, 0) 
('Request', 1459368705.785769) 
200 
('**** Response', 1459368705.786772, 141486) 
301 
('**** Response', 1459368706.110865, 0) 
('Request', 1459368706.114921) 
200 
('**** Response', 1459368706.116124, 141448) 
301 
('**** Response', 1459368706.396807, 0) 
('Request', 1459368706.400795) 
200 
301 
('**** Response', 1459368706.756861, 0) 
('Request', 1459368706.76069) 
200 
('**** Response', 1459368706.763268, 141448) 
('**** Response', 1459368706.488708, 141448) 
301 
('**** Response', 1459368707.065011, 0) 
('Request', 1459368707.069128) 
200 
('**** Response', 1459368707.071981, 141448) 
301 
('**** Response', 1459368707.366737, 0) 
('Request', 1459368707.370713) 
200 
('**** Response', 1459368707.373597, 141448) 
301 
('**** Response', 1459368707.73689, 0) 
200 
('**** Response', 1459368707.743815, 141448) 
200 
('**** Response', 1459368707.902499, 141448) 

Nếu chúng ta chạy cùng mã sử dụng một trang web phục vụ trên https, https://www.google.ie/ trong ví dụ này:

In [14]: for i in range(10): 
    ....:   unsent = grequests.get("https://www.google.ie/", hooks={'response': cb}) 
    ....:   print("Request", time.time()) 
    ....:   grequests.send(unsent, grequests.Pool(1)) 
    ....:   gevent.sleep(0.2) 
    ....: gevent.sleep(5) 
    ....: 
('Request', 1459368895.525717) 
200 
('**** Response', 1459368895.838453, 19682) 
('Request', 1459368895.884151) 
200 
('**** Response', 1459368896.168789, 19650) 
('Request', 1459368896.22553) 
200 
('**** Response', 1459368896.491304, 19632) 
('Request', 1459368896.542206) 
200 
('**** Response', 1459368896.808875, 19650) 
('Request', 1459368896.850575) 
200 
('**** Response', 1459368897.144725, 19705) 
('Request', 1459368897.173744) 
200 
('**** Response', 1459368897.45713, 19649) 
('Request', 1459368897.491821) 
200 
('**** Response', 1459368897.761675, 19657) 
('Request', 1459368897.792373) 
200 
('**** Response', 1459368898.331791, 19683) 
('Request', 1459368898.350483) 
200 
('**** Response', 1459368898.836108, 19713) 
('Request', 1459368898.855729) 
200 
('**** Response', 1459368899.148171, 19666) 

Bạn sẽ thấy hành vi khác. Chúng tôi nhận được 10 câu trả lời và không có phản hồi về độ dài 0. Bạn nên kiểm tra các status_code trong chức năng của bạn để xác minh bạn có được những gì bạn muốn. Ví dụ trên giải thích những gì bạn thấy cho trang web bbc và rất có thể điều gì đang xảy ra cho những người khác.

+0

Ok, điều đó giải thích phản hồi độ dài 0. Bạn nói đúng, nó không xảy ra trên các tên miền khác. Bất kỳ ý tưởng về việc chặn? – akxlr