我看到一些http处理程序函数声明是多种多样的。 我发现其中两个是标准函数,一个在处理程序中返回匿名函数。 例如:
使用标准方式:
func helloworld(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello World")
}
这是为http api声明处理程序的最直接方式。
另一种方法是在处理函数中使用anonym / closure函数:
func helloworld2() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
fmt.Fprintln(w, "Hello World")
})
}
有什么区别和好处?什么时候使用其中之一?什么是最佳做法?
答案 0 :(得分:6)
模式
func Middleware(next http.Handler) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do something
next.ServeHTTP(w, r)
})
}
经常用于构建像
这样的中间件链http.Handle("/", middlewareOne(middlewareTwo(finalHandler)))
答案 1 :(得分:5)
通过返回闭包,返回匿名函数是处理需要其他参数的处理程序的唯一方法。例如:
func fooHandler(db *someDatabase) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// do something with `db` variable
}
}
否则,这些方法之间通常没有实际差异。人们可以选择普遍使用匿名函数来保持一致性。
答案 2 :(得分:2)
关于结构返回匿名函数的最流行信息之一是Mat Ryer How I write HTTP services after eight years
的博客文章。我肯定会在这里提供他的文章的一些引言:
...处理程序函数实际上并不处理请求,它们返回的函数可以处理请求。这为我们的处理程序可以在其中提供一个封闭环境:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutterlearningapp/colors.dart';
class HomeScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomeScreen();
}
}
class _HomeScreen extends State<HomeScreen> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
appBar: AppBar(
title: Text("Demo Scroll"),
),
body: Container(
height: double.infinity,
width: double.infinity,
color: Colors.white,
child: Column(
children: <Widget>[
RaisedButton(
child: Text("Shoring"),
onPressed: (){
setState(() {
fields.sort((a, b) => a.rating.compareTo(b.rating));
});
},
),
Expanded(
child: ListView.builder
(
itemCount: fields.length,
itemBuilder: (BuildContext ctxt, int index) {
return ListTile(
title: new Text("Rating #${fields[index].rating}"),
subtitle: new Text(fields[index].title),
);
}
) ,
)
],
),
),
));
}
}
class Fields {
final String title;
final int rating;
Fields(this.title, this.rating);
}
List<Fields> fields = [
new Fields(
'Two',
2,
),
new Fields(
'One',
1,
),
new Fields(
'DEFAULT CATEGORY',
5,
),
new Fields(
'Three',
3,
),
new Fields(
'Four',
4,
),
];
prepareThing仅被调用一次,因此您可以使用它一次执行 每个处理程序初始化,然后在处理程序中使用它。
也是
如果端点具有自己的请求和响应类型,通常它们仅对特定处理程序有用。如果是这样,您可以在函数中定义它们。
func (s *server) handleSomething() http.HandlerFunc {
thing := prepareThing()
return func(w http.ResponseWriter, r *http.Request) {
// use thing
}
}
}
在实践中,编写RESTy API时,您有以资源命名的处理程序,例如您拥有/ maps资源和适当的处理程序结构mapsHandler,并在其中注入了相关性(存储库,包含一些业务逻辑的服务,记录器)。但是有时您还需要专门为每个句柄传递一个附加的依赖项,突然意识到处理程序具有严格的签名,因此您应该包装它。然后,您会遇到类似
func (s *server) handleSomething() http.HandlerFunc {
// you have these handy structs always visible to your handler and eyes
// and invisible to code that don't use them
type request struct {
Name string
}
type response struct {
Greeting string `json:"greeting"`
}
return func(w http.ResponseWriter, r *http.Request) {
// decode into request struct
// validate
// call business-logic
// encode response from business-logic into response struct
}
使您的临时依赖对处理程序可见。
希望有帮助!