Go هي لغة برمجة موجهة للشبكات ، وفي الحقيقة ، فإن المكتبة القياسية لديها لغة برمجة قوية جدًاnet/http
الوحدة النمطية ، وكتاب "لغة برمجة Go" من تأليف دونوفان وكيرنيغان يحتوي على مثال لخادم الويبفي الفصل الأول:
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
package main
import (
“fmt”
“log”
“net/http”
)
func main() {
http.HandleFunc("/", handler) // each request calls handler
log.Fatal(http.ListenAndServe(“localhost:8000”, nil))
}
// handler echoes the Path component of the requested URL.
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, “URL.Path = %q\n”, r.URL.Path)
}
هذا هو الشكل الأساسي لخادم HTTP.
اكتبgo run filename.go
والخادم نشط ، ويقبل الطلبات الواردة.
الhandler
تأخذ الوظيفة واجهة ResponseWriter ، والتي تتيح لنا إعادة الكتابة إلى العميل وتفاصيل طلب HTTP.
http.Request
يعرض الكثير من المعلومات حول الطلب الوارد:
type Request struct {
// Method specifies the HTTP method (GET, POST, PUT, etc.).
// For client requests an empty string means GET.
Method string
<span style="color:#75715e">// URL specifies either the URI being requested (for server
// requests) or the URL to access (for client requests).
//
// For server requests the URL is parsed from the URI
// supplied on the Request-Line as stored in RequestURI. For
// most requests, fields other than Path and RawQuery will be
// empty. (See RFC 2616, Section 5.1.2)
//
// For client requests, the URL’s Host specifies the server to
// connect to, while the Request’s Host field optionally
// specifies the Host header value to send in the HTTP
// request.
URL *url.URL
<span style="color:#75715e">// The protocol version for incoming server requests.
//
// For client requests these fields are ignored. The HTTP
// client code always uses either HTTP/1.1 or HTTP/2.
// See the docs on Transport for details.
Proto string // “HTTP/1.0”
ProtoMajor int // 1
ProtoMinor int // 0
// Header contains the request header fields either received
// by the server or to be sent by the client.
//
// If a server received a request with header lines,
//
// Host: example.com
// accept-encoding: gzip, deflate
// Accept-Language: en-us
// fOO: Bar
// foo: two
//
// then
//
// Header = map[string][]string{
// “Accept-Encoding”: {“gzip, deflate”},
// “Accept-Language”: {“en-us”},
// “Foo”: {“Bar”, “two”},
// }
//
// For incoming requests, the Host header is promoted to the
// Request.Host field and removed from the Header map.
//
// HTTP defines that header names are case-insensitive. The
// request parser implements this by using CanonicalHeaderKey,
// making the first character and any characters following a
// hyphen uppercase and the rest lowercase.
//
// For client requests, certain headers such as Content-Length
// and Connection are automatically written when needed and
// values in Header may be ignored. See the documentation
// for the Request.Write method.
Header Header
<span style="color:#75715e">// Body is the request's body.
//
// For client requests a nil body means the request has no
// body, such as a GET request. The HTTP Client’s Transport
// is responsible for calling the Close method.
//
// For server requests the Request Body is always non-nil
// but will return EOF immediately when no body is present.
// The Server will close the request body. The ServeHTTP
// Handler does not need to.
Body io.ReadCloser
<span style="color:#75715e">// GetBody defines an optional func to return a new copy of
// Body. It is used for client requests when a redirect requires
// reading the body more than once. Use of GetBody still
// requires setting Body.
//
// For server requests it is unused.
GetBody func() (io.ReadCloser, error)
<span style="color:#75715e">// ContentLength records the length of the associated content.
// The value -1 indicates that the length is unknown.
// Values >= 0 indicate that the given number of bytes may
// be read from Body.
// For client requests, a value of 0 with a non-nil Body is
// also treated as unknown.
ContentLength int64
<span style="color:#75715e">// TransferEncoding lists the transfer encodings from outermost to
// innermost. An empty list denotes the “identity” encoding.
// TransferEncoding can usually be ignored; chunked encoding is
// automatically added and removed as necessary when sending and
// receiving requests.
TransferEncoding []string
<span style="color:#75715e">// Close indicates whether to close the connection after
// replying to this request (for servers) or after sending this
// request and reading its response (for clients).
//
// For server requests, the HTTP server handles this automatically
// and this field is not needed by Handlers.
//
// For client requests, setting this field prevents re-use of
// TCP connections between requests to the same hosts, as if
// Transport.DisableKeepAlives were set.
Close bool
<span style="color:#75715e">// For server requests Host specifies the host on which the
// URL is sought. Per RFC 2616, this is either the value of
// the “Host” header or the host name given in the URL itself.
// It may be of the form “host:port”. For international domain
// names, Host may be in Punycode or Unicode form. Use
// golang.org/x/net/idna to convert it to either format if
// needed.
//
// For client requests Host optionally overrides the Host
// header to send. If empty, the Request.Write method uses
// the value of URL.Host. Host may contain an international
// domain name.
Host string
<span style="color:#75715e">// Form contains the parsed form data, including both the URL
// field’s query parameters and the POST or PUT form data.
// This field is only available after ParseForm is called.
// The HTTP client ignores Form and uses Body instead.
Form url.Values
<span style="color:#75715e">// PostForm contains the parsed form data from POST, PATCH,
// or PUT body parameters.
//
// This field is only available after ParseForm is called.
// The HTTP client ignores PostForm and uses Body instead.
PostForm url.Values
<span style="color:#75715e">// MultipartForm is the parsed multipart form, including file uploads.
// This field is only available after ParseMultipartForm is called.
// The HTTP client ignores MultipartForm and uses Body instead.
MultipartForm *multipart.Form
<span style="color:#75715e">// Trailer specifies additional headers that are sent after the request
// body.
//
// For server requests the Trailer map initially contains only the
// trailer keys, with nil values. (The client declares which trailers it
// will later send.) While the handler is reading from Body, it must
// not reference Trailer. After reading from Body returns EOF, Trailer
// can be read again and will contain non-nil values, if they were sent
// by the client.
//
// For client requests Trailer must be initialized to a map containing
// the trailer keys to later send. The values may be nil or their final
// values. The ContentLength must be 0 or -1, to send a chunked request.
// After the HTTP request is sent the map values can be updated while
// the request body is read. Once the body returns EOF, the caller must
// not mutate Trailer.
//
// Few HTTP clients, servers, or proxies support HTTP trailers.
Trailer Header
<span style="color:#75715e">// RemoteAddr allows HTTP servers and other software to record
// the network address that sent the request, usually for
// logging. This field is not filled in by ReadRequest and
// has no defined format. The HTTP server in this package
// sets RemoteAddr to an “IP:port” address before invoking a
// handler.
// This field is ignored by the HTTP client.
RemoteAddr string
<span style="color:#75715e">// RequestURI is the unmodified Request-URI of the
// Request-Line (RFC 2616, Section 5.1) as sent by the client
// to a server. Usually the URL field should be used instead.
// It is an error to set this field in an HTTP client request.
RequestURI string
<span style="color:#75715e">// TLS allows HTTP servers and other software to record
// information about the TLS connection on which the request
// was received. This field is not filled in by ReadRequest.
// The HTTP server in this package sets the field for
// TLS-enabled connections before invoking a handler;
// otherwise it leaves the field nil.
// This field is ignored by the HTTP client.
TLS *tls.ConnectionState
<span style="color:#75715e">// Cancel is an optional channel whose closure indicates that the client
// request should be regarded as canceled. Not all implementations of
// RoundTripper may support Cancel.
//
// For server requests, this field is not applicable.
//
// Deprecated: Use the Context and WithContext methods
// instead. If a Request’s Cancel field and context are both
// set, it is undefined whether Cancel is respected.
Cancel <-chan struct{}
<span style="color:#75715e">// Response is the redirect response which caused this request
// to be created. This field is only populated during client
// redirects.
Response *Response
// contains filtered or unexported fields
}
في هذه الحالة ، نحن مهتمون بـr.URL
، بنية عنوان URL المحددة في حزمة net.url:
type URL struct {
Scheme string
Opaque string // encoded opaque data
User *Userinfo // username and password information
Host string // host or host:port
Path string
RawPath string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
ForceQuery bool // append a query ('?') even if RawQuery is empty
RawQuery string // encoded query values, without '?'
Fragment string // fragment for references, without '#'
}
r.URL.Path
يطبع المسار المطلوب حاليًا ، لذا - باختصار - خادم الويب الذي كتبناه للتو في الوقت الحالي هو صدى بسيط لعنوان URL للطلب.
معالجات الطلبات المتعددة
كيف يمكنك إعداد معالج طلب ثانٍ لمسار معين ، والسماح للمعالج الأصلي بإدارة جميع طلبات المسار الأخرى؟
package main
import (
“fmt”
“log”
“sync”
)
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/about", aboutHandler)
log.Fatal(http.ListenAndServe(“localhost:8000”, nil))
}
// handler echoes the Path component of the requested URL.
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, “URL.Path = %q\n”, r.URL.Path)
}
// counter echoes the number of calls so far.
func aboutHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, “URL.Path = %q\n”, r.URL.Path)
//…
}
هنا كل الطلباتأيلا يزال يتم التعامل مع URL بواسطةhandler()
، يستثني/count
. هذا لأن تمريرpattern
تنتهي المعلمة بـ/
إلىhttp.HandleFunc()
سيؤدي إلى تطابق جميع الإجراءات الفرعية ، باستثناء العثور على واحد أكثر تخصصًا.
الوصول إلى الموارد
يوفر مثال خادم الويب الثاني طريقة للمعالجين لإدارة الموارد المشتركة في بيئة التزامن.
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
package main
import (
“fmt”
“log”
“net/http”
“sync”
)
var mu sync.Mutex
var count int
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/count", counter)
log.Fatal(http.ListenAndServe(“localhost:8000”, nil))
}
// handler echoes the Path component of the requested URL.
func handler(w http.ResponseWriter, r *http.Request) {
mu.Lock()
count++
mu.Unlock()
fmt.Fprintf(w, “URL.Path = %q\n”, r.URL.Path)
}
// counter echoes the number of calls so far.
func counter(w http.ResponseWriter, r *http.Request) {
mu.Lock()
fmt.Fprintf(w, “Count %d\n”, count)
mu.Unlock()
}
يستخدم هذا المثال كائن المزامنة لأنه داخليًاhttp.HandleFun()
الاستخداماتgoroutinesلإطلاق معالجات الطلب ، وhandler()
دالة على متغير الحزمة. لتجنب أحالة السباقمن الحدوث ، يجب علينا استدعاء Mutex.Lock قبل تغيير قيمته (نفس الشيء ينطبق علىcounter()
عند طباعة قيمته).
طباعة رؤوس الطلب
يقدم الكتاب أيضًا نموذج معالج تتمثل مهمته في طباعة رؤوس الطلب بتنسيق جيد:
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// handler echoes the HTTP request.
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto)
for k, v := range r.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
fmt.Fprintf(w, "Host = %q\n", r.Host)
fmt.Fprintf(w, "RemoteAddr = %q\n", r.RemoteAddr)
if err := r.ParseForm(); err != nil {
log.Print(err)
}
for k, v := range r.Form {
fmt.Fprintf(w, "Form[%q] = %q\n", k, v)
}
}
سيؤدي فتح الخادم في المتصفح إلى هذا الإخراج ، على سبيل المثال:
GET / HTTP/1.1
Header["Connection"] = ["keep-alive"]
Header["Accept"] = ["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"]
Header["Accept-Language"] = ["en-us"]
Header["Accept-Encoding"] = ["gzip, deflate"]
Header["Upgrade-Insecure-Requests"] = ["1"]
Header["User-Agent"] = ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.1 Safari/603.1.30"]
Header["Dnt"] = ["1"]
Host = "localhost:8000"
RemoteAddr = "127.0.0.1:51774"
المزيد من دروس Go:
- استخدام وكيل NGINX العكسي لخدمة خدمات Go
- عمل نسخة من هيكل في Go
- أساسيات Go Web Server
- فرز نوع الخريطة في Go
- الذهاب المؤشرات باختصار
- وأوضح Go Tags
- الذهاب تنسيق التاريخ والوقت
- معالجة JSON باستخدام Go
- وظائف متنوعة
- ورقة الغش Go Strings
- شرح واجهة Go Empty
- تصحيح الأخطاء الذهاب مع VS Code و Delve
- تقوم Named Go بإرجاع المعلمات
- توليد أرقام وسلاسل عشوائية في Go
- بنية نظام الملفات لمشروع Go
- تم تنفيذ خوارزمية البحث الثنائي في Go
- استخدام إشارات سطر الأوامر في Go
- أوضح جوباته
- أنشئ تطبيق Command Line باستخدام Go: lolcat
- إنشاء أمر CLI باستخدام Go: cowsay
- استخدام أنابيب شل مع Go
- Go CLI التعليمي: Fortune clone
- ضع قائمة بالملفات في مجلد باستخدام Go
- استخدم Go للحصول على قائمة بالمستودعات من GitHub
- اذهب ، قم بإلحاق شريحة من السلاسل بملف
- اذهب ، قم بتحويل سلسلة إلى شريحة بايت
- تصور مساهمات Git المحلية الخاصة بك مع Go
- الشروع في استخدام Go CPU وتوصيف الذاكرة
- حل الخطأ "لا يدعم الفهرسة" في برنامج Go
- قياس وقت التنفيذ في برنامج Go
- بناء زاحف الويب باستخدام Go لاكتشاف العناوين المكررة
- Go Best Practices: المؤشر أم مستقبلات القيمة؟
- Go Best Practices: هل يجب عليك استخدام طريقة أم دالة؟
- Go Data Structures: Set
- ورقة الغش في خرائط Go
- إنشاء تطبيقات لأنواع عامة في Go
- Go Data Structures: القاموس
- Go هياكل البيانات: Hash Table
- تنفيذ مستمعي الأحداث في الانتقال عبر القنوات
- Go Data Structures: Stack
- Go هياكل البيانات: قائمة الانتظار
- Go Data Structures: Binary Search Tree
- Go هياكل البيانات: رسم بياني
- Go Data Structures: قائمة مرتبطة
- الدليل الكامل إلى Go Data Structures
- مقارنة قيم Go
- هل Go موجه للكائن؟
- العمل مع قاعدة بيانات SQL في Go
- استخدام متغيرات البيئة في Go
- Go البرنامج التعليمي: REST API مدعوم من PostgreSQL
- تمكين CORS على خادم Go Web
- نشر تطبيق Go في حاوية Docker
- لماذا Go هي لغة قوية للتعلم كمطور PHP
- اذهب ، قم بإزالة io.Reader.ReadString حرف سطر جديد
- اذهب ، كيف تراقب التغييرات وتعيد بناء برنامجك
- اذهب وعد الأشهر منذ تاريخ
- الوصول إلى معلمات HTTP POST في Go