2008-12-03 7 views
35

मैं एक पायथन कार्यक्रम के लिए एक बहुत ही सरल HTML/AJAX आधारित जीयूआई बनाना चाहता हूं। तो फ्रंटएंड एक HTML पृष्ठ है जो प्रोग्राम के साथ AJAX के माध्यम से संचार करता है। क्या आप मुझे पाइथन SimpleHTTPServer.SimpleHTTPRequestHandler का उपयोग कर सर्वर-साइड के लिए न्यूनतम कार्यान्वयन दे सकते हैं?पायथन में AJAX के लिए न्यूनतम सर्वर को कैसे कार्यान्वित करें?

एक साधारण उदाहरण किसी पाठ फ़ील्ड और एक बटन होगा। जब बटन दबाया जाता है तो फ़ील्ड की सामग्री सर्वर को भेजी जाती है जो उसके बाद एक संबंधित उत्तर भेजती है। मुझे पता है कि पाइथन में इसके लिए कई शक्तिशाली समाधान हैं, लेकिन मैं इसे बहुत सरल रखना चाहता हूं। मुझे पहले से ही ऐसे सर्वर के लिए कुछ अच्छे उदाहरण मिल गए हैं (उदा। here), लेकिन अब तक मैं वास्तव में कम से कम एक के साथ नहीं आ सकता था।

यदि आपको आश्चर्य है कि मैं जीयूआई को इस तरह से क्यों कार्यान्वित करना चाहता हूं: इस एप्लिकेशन के लिए मेरा ध्यान केवल न्यूनतम इंटरैक्शन के साथ एक अच्छा लेआउट में बहुत सारे डेटा प्रदर्शित करना है - इसलिए HTML + CSS का उपयोग करना सबसे सुविधाजनक लगता है (और मैं पहले से ही गैर-इंटरैक्टिव डेटा डिस्प्ले के लिए इसका उपयोग कर रहा हूं)।

उत्तर

48

ठीक है, मुझे लगता है कि अब मैं अपने ही सवाल का जवाब कर सकते हैं। यहां सर्वर पर किसी संख्या के वर्ग की गणना करने के लिए एक उदाहरण कार्यान्वयन है। अगर कोई सुधार या गलत धारणाएं हैं तो कृपया मुझे बताएं।

अजगर सर्वर फ़ाइल:

import threading 
import webbrowser 
import BaseHTTPServer 
import SimpleHTTPServer 

FILE = 'frontend.html' 
PORT = 8080 


class TestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 
    """The test example handler.""" 

    def do_POST(self): 
     """Handle a post request by returning the square of the number.""" 
     length = int(self.headers.getheader('content-length'))   
     data_string = self.rfile.read(length) 
     try: 
      result = int(data_string) ** 2 
     except: 
      result = 'error' 
     self.wfile.write(result) 


def open_browser(): 
    """Start a browser after waiting for half a second.""" 
    def _open_browser(): 
     webbrowser.open('http://localhost:%s/%s' % (PORT, FILE)) 
    thread = threading.Timer(0.5, _open_browser) 
    thread.start() 

def start_server(): 
    """Start the server.""" 
    server_address = ("", PORT) 
    server = BaseHTTPServer.HTTPServer(server_address, TestHandler) 
    server.serve_forever() 

if __name__ == "__main__": 
    open_browser() 
    start_server() 

... और HTML फ़ाइल (मैं इसे 'frontend.html' कहते हैं, दुर्भाग्य से नाम जावा स्क्रिप्ट कोड में दिखाई देना चाहिए और साथ ही):

<html> 
<head> 
<title>AJAX test</title> 
</head> 
<body> 
<script type="text/javascript"> 

function xml_http_post(url, data, callback) { 
    var req = false; 
    try { 
     // Firefox, Opera 8.0+, Safari 
     req = new XMLHttpRequest(); 
    } 
    catch (e) { 
     // Internet Explorer 
     try { 
      req = new ActiveXObject("Msxml2.XMLHTTP"); 
     } 
     catch (e) { 
      try { 
       req = new ActiveXObject("Microsoft.XMLHTTP"); 
      } 
      catch (e) { 
       alert("Your browser does not support AJAX!"); 
       return false; 
      } 
     } 
    } 
    req.open("POST", url, true); 
    req.onreadystatechange = function() { 
     if (req.readyState == 4) { 
      callback(req); 
     } 
    } 
    req.send(data); 
} 

function test_button() { 
    var data = document.test_form.test_text.value;   
    xml_http_post("frontend.html", data, test_handle) 
} 

function test_handle(req) { 
    var elem = document.getElementById('test_result') 
    elem.innerHTML = req.responseText 
} 

</script> 

<form name=test_form> 
sqr(
<input type="text" name="test_text" value="0" size="4"> 
) = 
<span id="test_result">0</span> 
<input type=button onClick="test_button();" value="start" title="start"> 
</form> 

</body> 
</html> 

बेशक यह एक्सएमएल अनुरोध के लिए jQuery का उपयोग करना अधिक सुविधाजनक होगा, लेकिन सादगी के हित में मैं इसे छोड़ दूंगा। एक बहुत ही सहज ज्ञान युक्त के लिए

import threading 
import webbrowser 
from wsgiref.simple_server import make_server 

FILE = 'frontend.html' 
PORT = 8080 

def test_app(environ, start_response): 
    if environ['REQUEST_METHOD'] == 'POST': 
     try: 
      request_body_size = int(environ['CONTENT_LENGTH']) 
      request_body = environ['wsgi.input'].read(request_body_size) 
     except (TypeError, ValueError): 
      request_body = "0" 
     try: 
      response_body = str(int(request_body) ** 2) 
     except: 
      response_body = "error" 
     status = '200 OK' 
     headers = [('Content-type', 'text/plain')] 
     start_response(status, headers) 
     return [response_body] 
    else: 
     response_body = open(FILE).read() 
     status = '200 OK' 
     headers = [('Content-type', 'text/html'), 
        ('Content-Length', str(len(response_body)))] 
     start_response(status, headers) 
     return [response_body] 

def open_browser(): 
    """Start a browser after waiting for half a second.""" 
    def _open_browser(): 
     webbrowser.open('http://localhost:%s/%s' % (PORT, FILE)) 
    thread = threading.Timer(0.5, _open_browser) 
    thread.start() 

def start_server(): 
    """Start the server.""" 
    httpd = make_server("", PORT, test_app) 
    httpd.serve_forever() 

if __name__ == "__main__": 
    open_browser() 
    start_server() 
+2

बस तुलना के लिए, यहां एक रामज़ उदाहरण है: http://news.ycombinator.com/item?id=383960 – jfs

+0

"क्या कोई पायदान नहीं है तो मानक पायथन हैंडलर पर वापस आने का कोई तरीका है?" ज्यादा मतलब नहीं है। आपको लगता है कि "मानक" हैंडलर क्या है? –

+0

एसएलओटी: पहले सर्वर कार्यान्वयन में SimpleHTTPRequestHandler का व्यवहार केवल POST अनुरोधों के लिए बदला जाता है। इसलिए HTML फ़ाइल लोड हो रहा है इसलिए किसी भी अतिरिक्त कोड की आवश्यकता नहीं है। डब्लूएसजीआई कार्यान्वयन में मुझे स्पष्ट रूप से HTML भेजना है, जीईटी स्वचालित रूप से संभाला नहीं जाता है। – nikow

9

उपयोग WSGI reference implementation। लंबे समय तक, आप खुश रहेंगे।

from wsgiref.simple_server import make_server, demo_app 

httpd = make_server('', 8000, demo_app) 
print "Serving HTTP on port 8000..." 

# Respond to requests until process is killed 
httpd.serve_forever() 

demo_app लिखने के लिए अपेक्षाकृत आसान है; यह आपके अजाक्स अनुरोधों को संभालता है।

+0

से केएस, मैं अंततः एक साधारण उदाहरण बनाने में कामयाब रहा (नीचे मेरा जवाब देखें)। – nikow

+0

दिलचस्प लगता है। क्या आप समझा सकते हैं कि 'बेसएचटीटीपीएसवर' दृष्टिकोण के लिए यह बेहतर क्यों है? – FriendFX

0

धन्यवाद:

अंत में एक विकल्प के WSGI का उपयोग कर कार्यान्वयन (दुर्भाग्य से मैं एक तरह से मानक फ़ाइल सेवारत हैंडलर पर वापस आने का अनुरोध करता है, तो एक पोस्ट नहीं है नहीं देखा) उदाहरण @nikow मैं अपने उदाहरण का अनुसरण करने की कोशिश कर रहा था, लेकिन एक त्रुटि मिला:

(प्रक्रिया: 10281): चिकना-महत्वपूर्ण **: g_slice_set_config: अभिकथन 'sys_page_size == 0' विफल

मैं संशोधित एम से मिलने के लिए आपका कोड एम वाई जरूरत है

webbrowser.open('file:///home/jon/workspace/webpages/frontend_example/%s' % FILE) 
// skipped the port part 
httpd = make_server("", 8080, test_app) 
// hardcoded it here. 

क्या मेरी एचटीएमएल फाइल को वेबसर्वर पर रखा जाना है? मैंने इसे अभी तक नहीं रखा है!

+0

हां, मेरे उदाहरण में फ़ाइल वेबसर्वर द्वारा परोसा जाता है, इसलिए इसे वहां उपलब्ध होना चाहिए। – nikow

0

यहाँ @ nikow के उदाहरण

के आधार पर मैं जानता हूँ कि यह त्रुटियों हो सकता है, टिप्पणी होते हैं क्या हुआ अगर आप उन्हें खोजने के अजगर 3 के लिए एक सरल उदाहरण है।

कोड स्ट्रिंग भेजता है जब आप रन पर क्लिक करें, अजगर के साथ "मैं समझ गया" प्रतिक्रिया करता

एचटीएमएल कोड "मैं आपको यह संदेश भेजा"

(आप करने वाले हैं js कंसोल का उपयोग करने के लिए है इस के लिए)

<body> 
<button id="runButton">Run</button> 
<script type="text/javascript"> 
function xml_http_post(url, data) { 
var req = new XMLHttpRequest(); 
req.open("POST", url, true); 
req.onreadystatechange = function() { 
    if (req.readyState == 4) { 
    console.log(req.responseText); 
    } 
} 
req.send(data); 
} 

function runbuttonfunc() { 
    xml_http_post("frontend.html", "I sent you this message") 
} 

document.getElementById("runButton").onclick = runbuttonfunc; 
</script> 
</body> 

अजगर कोड: आयात http.server

FILE = 'frontend.html' 
PORT = 8000 


class TestHandler(http.server.SimpleHTTPRequestHandler): 
    """The test example handler.""" 

    def do_POST(self): 
     """Handle a post request by returning the square of the number.""" 
     print(self.headers) 
     length = int(self.headers.get_all('content-length')[0]) 
     print(self.headers.get_all('content-length')) 
     data_string = self.rfile.read(length) 
     print(data_string) 
     self.send_response(200) 
     self.send_header("Content-type", "text/plain") 
     self.end_headers() 
     self.flush_headers() 
     self.wfile.write("I got it!".encode()) 


def start_server(): 
    """Start the server.""" 
    server_address = ("", PORT) 
    server = http.server.HTTPServer(server_address, TestHandler) 
    server.serve_forever() 

start_server() 
संबंधित मुद्दे

 संबंधित मुद्दे