2012-05-23 12 views
28

Tôi đã chơi đùa với Tornado và tôi đã viết một số mã có vẻ không hay lắm.Thông số truy vấn URL Tornado

Tôi đang viết một ứng dụng để lưu trữ công thức nấu ăn làm ví dụ. Đây là những xử lý của tôi:

handlers = [ 
    (r"/recipes/", RecipeHandler), 
    (r"/recipes", RecipeSearchHandler), #so query params can be used to search 
] 

này đưa tôi đến với văn bản này:

class RecipeHandler(RequestHandler):  
    def get(self): 
     self.render('recipes/index.html') 

class RecipeSearchHandler(RequestHandler):  
    def get(self): 
     try: 
      name = self.get_argument('name', True) 
      self.write(name) 
     # will do some searching 
     except AssertionError: 
      self.write("no params") 
      # will probably redirect to /recipes/ 

Có cách nào tốt hơn để tiếp cận các URL mà không có một thử/trừ? Tôi muốn/công thức nấu ăn và/công thức nấu ăn/để hiển thị cùng một điều, trong khi/công thức nấu ăn? Tên = một cái gì đó sẽ làm một tìm kiếm, và lý tưởng là một xử lý khác nhau.

Trả lời

35

Có cách tốt hơn để yêu cầu GET. Có một bản demo trong nguồn cơn lốc xoáy trên github here

# url handler 
handlers = [(r"/entry/([^/]+)", EntryHandler),] 

class EntryHandler(BaseHandler): 
    def get(self, slug): 
     entry = self.db.get("SELECT * FROM entries WHERE slug = %s", slug) 
     if not entry: raise tornado.web.HTTPError(404) 
     self.render("entry.html", entry=entry) 

Bất kỳ "văn bản" phù hợp với biểu thức chính quy sẽ được chuyển đến method get của EntryHandler như là đối số sên. Nếu url không khớp với bất kỳ trình xử lý nào, người dùng sẽ nhận được lỗi 404.

Nếu bạn muốn cung cấp dự phòng khác, bạn có thể làm cho các tham số tùy chọn

(r"/entry/([^/]*)", EntryHandler), 

class EntryHandler(BaseHandler): 
    def get(self, slug=None): 
     pass 

Cập nhật:

+1 cho liên kết. Tuy nhiên không mẫu URL này mở rộng để bao gồm nhiều thông số nếu tôi muốn tìm kiếm như thế này ... /công thức nấu ăn thành phần = gà & style = Ấn Độ - colinjameswebb

Có nó.

handlers = [ 
    (r'/(\d{4})/(\d{2})/(\d{2})/([a-zA-Z\-0-9\.:,_]+)/?', DetailHandler) 
] 

class DetailHandler(BaseHandler): 
    def get(self, year, month, day, slug): 
     pass 
+2

1 cho liên kết. Tuy nhiên, mẫu URL này có mở rộng để bao gồm nhiều tham số hơn nếu tôi muốn tìm kiếm như thế này .../recipes? Ingredients = chicken & style = indian – colinjwebb

28

get_argument cho phép bạn để cung cấp một giá trị mặc định:

details=self.get_argument("details", None, True) 

Nếu nó được cung cấp, sau đó không có ngoại lệ sẽ xảy ra nếu đối số không được cung cấp

8

Tornado cũng có một chức năng get_arguments . Nó trả về một danh sách các đối số với tên đã cho. Nếu không có, nó sẽ trả về một danh sách trống ([]). Tôi tìm thấy nó sạch hơn theo cách này để khử trùng đầu vào dịch vụ web của bạn thay vì try..catch khối.

mẫu:
Giả sử tôi có một handler sau URL:

(r"/recipe",GetRecipe)

Và xử lý yêu cầu:

class GetRecipe(RequestHandler): 
    def get(self): 
     recipe_id = self.get_arguments("rid") 
     if recipe_id == []: 
      # Handle me 
      self.set_status(400) 
      return self.finish("Invalid recipe id") 
     self.write({"recipe_id":self.get_argument("rid")}) 


recipe_id danh sách cũng sẽ giữ giá trị nhưng tôi tìm thấy self.get_argument cách sử dụng thuận tiện theo cách này.

Bây giờ cho kết quả:

curl "http://localhost:8890/recipe" -v 

* Trying 127.0.0.1... 
* Connected to localhost (127.0.0.1) port 8890 (#0) 
> GET /recipe HTTP/1.1 
> User-Agent: curl/7.35.0 
> Host: localhost:8890 
> Accept: */* 
> 
< HTTP/1.1 400 Bad Request 
< Content-Length: 17 
< Content-Type: text/html; charset=UTF-8 
* Server TornadoServer/1.1.1 is not blacklisted 
< Server: TornadoServer/1.1.1 
< 
* Connection #0 to host localhost left intact 
Invalid recipe id 

curl "http://localhost:8890/recipe?rid=230" -v 
* Trying 127.0.0.1... 
* Connected to localhost (127.0.0.1) port 8890 (#0) 
> GET /recipe?rid=230 HTTP/1.1 
> User-Agent: curl/7.35.0 
> Host: localhost:8890 
> Accept: */* 
> 
< HTTP/1.1 200 OK 
< Content-Length: 20 
< Etag: "d69ecb9086a20160178ade6b13eb0b3959aa13c6" 
< Content-Type: text/javascript; charset=UTF-8 
* Server TornadoServer/1.1.1 is not blacklisted 
< Server: TornadoServer/1.1.1 
< 
* Connection #0 to host localhost left intact 
{"recipe_id": "230"} 

3

Nếu bạn muốn sử dụng một cách tiếp cận năng động hơn để lọc (thay vì một địa chỉ URL cứng mã hóa), bạn có thể nhận được tất cả các thông qua URL thông số/lập luận sử dụng self.request.arguments trong trình xử lý yêu cầu.

class ApiHandler(RequestHandler): 
    def get(self, path): 
     filters = self.request.arguments 
     for k,v in filters.items(): 
      # Do filtering etc... 

Xem http://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPServerRequest.arguments

+0

Gợi ý hay. Chỉ cần một nhận xét liên quan đến Unicode Strings. Tài liệu nói: Tên có kiểu str, trong khi các đối số là các chuỗi byte. Lưu ý rằng điều này khác với RequestHandler.get_argument, trả về các giá trị đối số dưới dạng các chuỗi unicode. – klaas