我创建了一个需要从 golang 后端加载的 flutter http 函数。我已经允许 go 后端中的所有来源,但 flutter web 仍然返回 cors 问题。我的 golang 版本可能有问题吗?或者也许是颤振网络? 以下是我的Go God:
func main() {
db, err := NewDB()
if err != nil {
panic("Failed to connect to database")
}
CreateTables(db)
// Seed currencies
if err := SeedCurrencies(db.DB); err != nil {
panic("failed to seed currencies")
}
config := cors.Config{
AllowOrigins: []string{"https://app.mam-laka.com", "*mam-laka.com", "*"}, // Allow all origins
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"}, // Allowed HTTP methods (adjust as needed)
AllowHeaders: []string{"Origin", "Content-Type", "Accept",
"Authorization", "Access-Control-Allow-Origin"}, // Allowed request headers
ExposeHeaders: []string{"Content-Length"}, // Headers that can be exposed to the browser
AllowCredentials: true, // Allows sending cookies and credentials like authorization tokens
MaxAge: 12 * time.Hour, // Cache preflight responses for 12 hours
}
r := SetupRouter(db)
r.Use(cors.New(config))
r.Run(":8091")
}
如上图,我已经处理了cors golang部分。在 flutter 代码中,该函数如下所示:
Future signIn() async {
Map<String, dynamic> body = {
"email": email.text,
"password": password.text,
};
try {
setState(() {
isLoading = true;
});
Map<String, String> headers = {
"Content-Type": "application/json",
};
var url = Uri.parse('$baseurl/login');
var response =
await http.post(url, headers: headers, body: jsonEncode(body));
Map data = jsonDecode(response.body);
print(data);
if (response.statusCode == 200 && data["message"] == "Login successful") {
var box = await Hive.box('myBox');
box.put('token', data['token']);
box.put('names', '${data['user']['fname']} ${data['user']['lname']}');
box.put('email', data['user']['email']);
print(box.get("email"));
print(box.get("names"));
Navigator.push(
context,
PageTransition(
type: PageTransitionType.rightToLeft,
child: Bottomnav(),
),
);
showTopSnackBar(
Overlay.of(context),
CustomSnackBar.success(
message: data["message"],
),
);
} else if (response.statusCode == 401) {
showTopSnackBar(
Overlay.of(context),
CustomSnackBar.error(
message: "Invalid credentials. Please try again.",
),
);
} else {
showTopSnackBar(
Overlay.of(context),
CustomSnackBar.error(
message: data["message"] ?? "An error occurred. Please try again.",
),
);
}
} catch (e) {
print("This is e $e");
showTopSnackBar(
Overlay.of(context),
const CustomSnackBar.error(
message: "Check your internet connection",
),
);
} finally {
setState(() {
isLoading = false;
});
}
}
CORS 每次只能接受一个值,因此您可以为所有值添加一个 FQDN 或 *。
我在下面留下了部分简单代码,例如如何在你的 api 代码中允许 CORS
// EXAMPLE TO USE CORS IN A GO API
package main
import (
"log"
"net/http"
"os"
"strings"
)
func apiHandler(w http.ResponseWriter, r *http.Request) {
// Set Content-Type based in the router {response}
contentType := r.Header.Get("Content-Type")
// allows the counterparty to define the content-type
switch contentType {
case "application/json":
w.Header().Set("Content-Type", "application/json")
case "text/plain":
w.Header().Set("Content-Type", "text/plain")
case "text/html":
w.Header().Set("Content-Type", "text/html")
case "application/xml":
w.Header().Set("Content-Type", "application/xml")
default:
w.Header().Set("Content-Type", "text/plain")
}
// CORS CONTROL
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Origin", "https://app.mam-laka.com")
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") // Other options: GET,PUT,POST,DELETE,PATCH,OPTIONS,HEAD
w.Header().Set("Vary", "Origin")
// CACHE AND CONTROL
w.Header().Set("Cache-Control", "no-cache, private, max-age=0") // "max-age=3600"
w.Header().Set("Pragma", "no-cache")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
// Obfuscating server information
serverHeader := "GO WebServer - I am a teapot"
w.Header().Set("Server", serverHeader)
// Get API name from Request
apiName := r.PathValue("api")
// Get API Authorization from Request (Bearer <token>)
authToken := r.Header.Get("Authorization")
// Split parameters and authorization from header
authParts := strings.Split(authToken, "Bearer ")
// Permit preflight CORS from Browsers and Deny Bearer Token missing
if len(authParts) < 2 {
http.Error(w, "%s", http.StatusOK) // Return status 200 to permit CORS check
return // Stop access and Deny continue
}
// If everything it's ok with Bearer Token get token from Authorization: Bearer <token>
apiKey := authParts[1]
// Set Bearer <token> to header
r.Header.Set("Authorization", "Bearer "+apiKey)
// Get URL
urlPath := r.URL.Path
// Check API to validate Key
/*
* Create your logic to control apiKey and who can access your system
*
*/
// Main API Proccess
/*
* Create your logic to permit access to your internal calls
* for example, you can create a internal function to pass apiName and other stuff's, something like:
* ok := api.GetLogin(&apiName, &urlPath, w)
*
*/
// If everything's OK return Status 200 or something like that
if ok == nil {
w.WriteHeader(http.StatusOK)
}
}
func main() {
// Check database availability (create your database connection first)
db, err := database.OpenConnection()
if err != nil {
log.Fatal("Error: Database connection failed")
}
db.Close()
// Initiate Web Server with handle
http.HandleFunc("/api/{api}/", apiHandler)
err = http.ListenAndServeTLS(":8091", "ssl/cert.pem", "ssl/cert.key", nil)
if err != nil {
log.Fatal("Web Server Error [check tcpPort and SSL Certs] ", err)
}
}
我知道这个例子不是你问题的正确答案,但我希望这个逻辑的一部分对你有帮助。
再见 亚历克斯·曼弗林 github.com/mitvix