英文:
rpc error: code = Unavailable desc = error reading from server: EOF resulting in a panic runtime error: invalid memory address error on goland
问题
我是新来的Stack Overflow用户,这是我的第一个问题,所以我非常乐意对它进行任何改进 当我运行一个测试方法来取消喜欢一件艺术品时,我遇到了一个问题。我有一个方法,允许用户喜欢特定的艺术品,这些艺术品由它们自己独立的艺术品UUID进行分类,该方法运行得很完美。我有一个console.proto文件,其中我指定了LikeArtwork和UnlikeArtwork方法的必要请求和响应消息,并在methods.go文件中创建了这些方法。我还有其他的方法正在测试,它们似乎都工作得很完美,只有UnlikeArtwork方法除外。
我有一个followUser和UnfollowUser方法,它们的工作方式完全相同,只是在UnfollowUser方法中,用户只是从包含所有关注者的"followers"切片/数组中移除。对于likeArtwork和UnlikeArtwork方法,概念完全相同,用户要么被添加到"likes"切片/数组中,要么被从中移除,这就是为什么我对它导致我的用户服务器崩溃并显示以下错误感到困惑:
[signal SIGSEGV: segmentation violation code=0x2 addr=0x58 pc=0x104d0b844]```
我的console.proto定义如下:
service Service {
// Registers a user on the hockney platform/ This entails creating the user
// using the CreateUser method and uploading their profile picture using the
// UploadProfilePicture method/ Down the line, this could also entail the
// creation of a custodian wallet for users as well/
rpc RegisterUser (RegisterUserRequest) returns (RegisterUserResponse) {}
// Follow user takes the user of the current session and updates their details
// and that of the followee to reflect the following
rpc FollowUser (FollowUserRequest) returns (FollowUserResponse) {}
// Like an artwork
rpc LikeArtwork (LikeArtworkRequest) returns (LikeArtworkResponse) {}
// Unfollow a user
rpc UnfollowUser (UnfollowUserRequest) returns (UnfollowUserResponse) {}
// Unlike an artwork
rpc UnlikeArtwork (UnlikeArtworkRequest) returns (UnlikeArtworkResponse) {}
// New UnLike an artwork method
rpc UnLikeArtwork (UnLikeArtworkRequest) returns (UnLikeArtworkResponse) {}
}
和,
// Request message for the FollowUser method
message FollowUserRequest {
// The user of the current session
// Format: users/{username}
string current_user = 1;
// The user to follow
// Format: users/{username}
string user_to_follow = 2;
}
// Response message for the FollowUser method
// Reserved for future use...
message FollowUserResponse {}
// Request message for LikeArtwork
message LikeArtworkRequest {
// The user that likes
// Format: users/{username}
string user = 1;
// The artwork that has been liked
// Format: artworks/{uuid}
string artwork = 2;
}
// Response message for LikeArtwork
message LikeArtworkResponse {}
// Request message for the UnfollowUser method
message UnfollowUserRequest {
// The user of the current session
// Format: users/{username}
string current_user = 1;
// The user to unfollow
// Format: users/{username}
string user_to_unfollow = 2;
}
// Response message for UnfollowUser method
message UnfollowUserResponse {}
// Request message for the UnlikeArtwork method
message UnlikeArtworkRequest {
// The user that unlikes
// Format: users/{username}
string user = 1;
// The artwork that has been unliked
// Format: artworks/{uuid}
string artwork_to_unlike = 2;
}
// Response message for the UnlikeArtwork method
message UnlikeArtworkResponse {}
我编写的取消喜欢艺术品的方法与LikeArtwork方法完全相同,只是从"likes"切片中移除了一个用户。这发生在```currentUser.Likes = append(...)...```这一行。我不认为问题出在这里,因为通过Goland调试器运行此代码时,错误似乎发生在函数的这部分之前。该方法的函数如下所示:
func (s *myService) UnlikeArtwork(ctx context.Context, req *pb.UnlikeArtworkRequest) (*pb.UnlikeArtworkResponse, error) {
currentUser, err := clients.Users.GetUser(ctx, &pbUsers.GetUserRequest{
Name: req.GetUser(),
ReadMask: &fieldmaskpb.FieldMask{Paths: []string{"likes"}},
})
if err != nil {
return nil, err
}
// Set new likes
//currentUser.Following = append(currentUser.Following[:sort.StringSlice(currentUser.Following).Search(req.GetUserToUnfollow())], currentUser.Following[sort.StringSlice(currentUser.Following).Search(req.GetUserToUnfollow())+1:]...)
currentUser.Likes = append(currentUser.Likes[:sort.StringSlice(currentUser.Likes).Search(req.GetUser())], currentUser.Likes[sort.StringSlice(currentUser.Likes).Search(req.GetUser())+1:]...)
// Update the current_user
_, err = clients.Users.UpdateUser(ctx, &pbUsers.UpdateUserRequest{
User: currentUser,
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"likes"}},
})
if err != nil {
return nil, err
}
currentArtwork, err := clients.Artworks.GetArtwork(ctx, &pbArtworks.GetArtworkRequest{
Name: req.GetArtworkToUnlike(),
ReadMask: &fieldmaskpb.FieldMask{Paths: []string{"likes"}},
})
if err != nil {
return nil, err
}
// Set the likes
//userToUnfollow.Followers = append(userToUnfollow.Followers[:sort.StringSlice(userToUnfollow.Followers).Search(req.GetCurrentUser())], userToUnfollow.Followers[sort.StringSlice(userToUnfollow.Followers).Search(req.GetCurrentUser())+1:]...)
currentArtwork.Likes = append(currentArtwork.Likes[:sort.StringSlice(currentArtwork.Likes).Search(req.GetArtworkToUnlike())], currentArtwork.Likes[sort.StringSlice(currentArtwork.Likes).Search(req.GetArtworkToUnlike())+1:]...)
// Update the current artwork
_, err = clients.Artworks.UpdateArtwork(ctx, &pbArtworks.UpdateArtworkRequest{
Artwork: currentArtwork,
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"likes"}},
})
if err != nil {
return nil, err
}
return &pb.UnlikeArtworkResponse{}, nil
}
然后在methods_test.go文件中运行测试,模拟函数本身和函数的输入。
func TestMyService_UnlikeArtwork(t *testing.T) {
req := pbConsole.UnlikeArtworkRequest{
User: "PurpleRaine",
ArtworkToUnlike: "artworks/0cca6063-7b6f-464a-ac88-dff8679a3905",
}
// Run a method
res, err := client.UnlikeArtwork(context.Background(), &req)
if err != nil {
t.Error(err)
}
log.Println(logging.Entry{Message: res.String()})
}
测试的输出是:
methods_test.go:111: rpc error: code = Unavailable desc = error reading from server: EOF
methods_test.go:114: {"message":"\u003cnil\u003e","severity":"INFO"}
--- FAIL: TestMyService_UnLikeArtwork (0.01s)
FAIL
并且这与我在问题开头列出的服务器崩溃错误一起发生。
**附加信息:**
我的用户服务器配置如下:
package main
import (
"context"
"fmt"
pb "github.com/jaebrownn/hockney/protobuf/go/hock/ap/resources/users/v1"
"google.golang.org/grpc"
"hock.ap.resources.users.v1/internal/logging"
"hock.ap.resources.users.v1/internal/methods"
"log"
"net"
"os"
)
// clients is a global clients, initialized once per cloud run instance.
var ()
func init() {
// Disable log prefixes such as the default timestamp.
// Prefix text prevents the message from being parsed as JSON.
// A timestamp is added when shipping logs to Cloud Logging.
log.SetFlags(0)
// TODO: implement when needed
// Ensure that required envs exist.
//if os.Getenv("ENV") == "" {
// log.Fatal("ENV env not set.")
//}
}
func main() {
log.Println(&logging.Entry{Message: "starting server...", Severity: logging.NOTICE})
port := os.Getenv("USERS_PORT")
if port == "" {
port = "8080"
log.Println(&logging.Entry{Message: "Defaulting to port " + port, Severity: logging.WARNING})
}
listener, err := net.Listen("tcp", ":"+port)
if err != nil {
log.Fatalf("net.Listen: %v", err)
}
grpcServer := grpc.NewServer(grpc.UnaryInterceptor(serverInterceptor))
pb.RegisterUsersServiceServer(grpcServer, &methods.MyService{})
if err = grpcServer.Serve(listener); err != nil {
log.Fatal(err)
}
}
// serverInterceptor is an example of a Server Interceptor which could be used to 'inject'
// for example logs and/or tracing details to incoming server requests.
// Add this method to your grpc server connection, for example
// grpcServer := grpc.NewServer(grpc.UnaryInterceptor(serverInterceptor))
//
// pb.RegisterServiceServer(grpcServer, &myService{})
func serverInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
// Calls the handler
h, err := handler(ctx, req)
if err != nil {
log.Println(&logging.Entry{Message: fmt.Sprintf("%v", req), Severity: logging.DEBUG, Ctx: ctx})
log.Println(&logging.Entry{Message: err.Error(), Severity: logging.WARNING, Ctx: ctx})
}
_ = info
return h, err
}
编辑:以下是崩溃发生时的完整堆栈跟踪:
goroutine 54 [running]:
cloud.google.com/go/firestore.(*DocumentSnapshot).DataTo(0x0?, {0x104e28820?, 0x140000d02c0?})
/Users/michaelaltshuler/go/pkg/mod/cloud.google.com/go/firestore@v1.6.1/document.go:112 +0x24
hock.ap.resources.users.v1/internal/methods.(*MyService).GetUser(0x1400011f9a8?, {0x104e4ea60, 0x14000102750}, 0x14?)
/Users/michaelaltshuler/GolandProjects/hockney/products/hock/ap/resources/users/v1/internal/methods/methods.go:59 +0x84
github.com/jaebrownn/hockney/protobuf/go/hock/ap/resources/users/v1._UsersService_GetUser_Handler.func1({0x104e4ea60, 0x14000102750}, {0x104dd2d40?, 0x14000046340})
/Users/michaelaltshuler/GolandProjects/hockney/protobuf/go/hock/ap/resources/users/v1/users_grpc.pb.go:212 +0x74
main.serverInterceptor({0x104e4ea60?, 0x14000102750}, {0x104dd2d40, 0x14000046340}, 0x1400011faa8?, 0x104a98c24?)
/Users/michaelaltshuler/GolandProjects/hockney/products/hock/ap/resources/users/v1/server.go:62 +0x3c
github.com/jaebrownn/hockney/protobuf/go/hock/ap/resources/users/v1._UsersService_GetUser_Handler({0x104dd7cc0?, 0x1052cdd08}, {0x104e4ea60, 0x14000102750}, 0x14000140000, 0x104e44430)
/Users/michaelaltshuler/GolandProjects/hockney/protobuf/go/hock/ap/resources/users/v1/users_grpc.pb.go:214 +0x138
google.golang.org/grpc.(*Server).processUnaryRPC(0x140000d63c0, {0x104e52278, 0x14000003860}, 0x140005a4000, 0x140000a08a0, 0x10528e3f8, 0x0)
/Users/michaelaltshuler/go/pkg/mod/google.golang.org/grpc@v1.48.0/server.go:1295 +0x9c4
google.golang.org/grpc.(*Server).handleStream(0x140000d63c0, {0x104e52278, 0x14000003860}, 0x140005a4000, 0x0)
/Users/michaelaltshuler/go/pkg/mod/google.golang.org/grpc@v1.48.0/server.go:1636 +0x82c
google.golang.org/grpc.(*Server).serveStreams.func1.2()
/Users/michaelaltshuler/go/pkg/mod/google.golang.org/grpc@v1.48.0/server.go:932 +0x84
created by google.golang.org/grpc.(*Server).serveStreams.func1
/Users/michaelaltshuler/go/pkg/mod/google.golang.org/grpc@v1.48.0/server.go:930 +0x290
当从这个堆栈跟踪导航到我的getUser方法时,它将我带到代码中的```err = dsnap.DataTo(user)```这一行:
dsnap, err := clients.Firestore.Doc(req.GetName()).Get(ctx)
//user message to return
user := &pb.User{}
err = dsnap.DataTo(user) // This line
if err != nil {
return nil, err
}
我知道这是一个非常冗长的方式来寻求关于这个问题的帮助。我在网上找到的资源非常少,希望这些信息有些意义,有人能够指导我朝正确的方向前进。谢谢!
<details>
<summary>英文:</summary>
I am new Stack Overflow and this is my first question so I'm very open and happy to make any improvements to it :)
I'm having an issue when I run a test method to unlike an artwork. I have a method that enables a user to like a specific artwork which is categorised by their own separate artwork uuid's, and the method works perfectly. I have a console.proto file where I specify the necessary request and response messages for both the LikeArtwork and UnlikeArtwork methods, and have created the methods themselves in a methods.go file. I have other methods that I am testing and they all seem to work perfectly except for the UnlikeArtwork method.
I have a followUser and UnfollowUser method, which both work in exactly the same way, except in the UnfollowUser method, a user is just removed from the "followers" slice/array that contains all of the followers. The concept is exactly the same for the likeArtwork and UnlikeArtwork methods where users are either added or removed from the "likes" slice/array, which is why I am so confused as to why it is causing my User's server to crash with the error:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x58 pc=0x104d0b844]
My console.proto is defined as follows:
service Service {
// Registers a user on the hockney platform/ This entails creating the user
// using the CreateUser method and uploading their profile picture using the
// UploadProfilePicture method/ Down the line, this could also entail the
// creation of a custodian wallet for users as well/
rpc RegisterUser (RegisterUserRequest) returns (RegisterUserResponse) {}
// Follow user takes the user of the current session and updates their details
// and that of the followee to reflect the following
rpc FollowUser (FollowUserRequest) returns (FollowUserResponse) {}
// Like an artwork
rpc LikeArtwork (LikeArtworkRequest) returns (LikeArtworkResponse) {}
// Unfollow a user
rpc UnfollowUser (UnfollowUserRequest) returns (UnfollowUserResponse) {}
// Unlike an artwork
rpc UnlikeArtwork (UnlikeArtworkRequest) returns (UnlikeArtworkResponse) {}
// New UnLike an artwork method
rpc UnLikeArtwork (UnLikeArtworkRequest) returns (UnLikeArtworkResponse) {}
}
and,
// Request message for the FollowUser method
message FollowUserRequest {
// The user of the current session
// Format: users/{username}
string current_user = 1;
// The user to follow
// Format: users/{username}
string user_to_follow = 2;
}
// Response message for the FollowUser method
// Reserved for future use...
message FollowUserResponse {}
// Request message for LikeArtwork
message LikeArtworkRequest {
// The user that likes
// Format: users/{username}
string user = 1;
// The artwork that has been liked
// Format: artworks/{uuid}
string artwork = 2;
}
// Response message for LikeArtwork
message LikeArtworkResponse {}
// Request message for the UnfollowUser method
message UnfollowUserRequest {
// The user of the current session
// Format: users/{username}
string current_user = 1;
// The user to unfollow
// Format: users/{username}
string user_to_unfollow = 2;
}
// Response message for UnfollowUser method
message UnfollowUserResponse {}
// Request message for the UnlikeArtwork method
message UnlikeArtworkRequest {
// The user that unlikes
// Format: users/{username}
string user = 1;
// The artwork that has been unliked
// Format: artworks/{uuid}
string artwork_to_unlike = 2;
}
// Response message for the UnlikeArtwork method
message UnlikeArtworkResponse {}
The method I wrote to unlike an artwork works in exactly the same way as the LikeArtwork method, however, a user is removed from the "likes" slice. This occurs when ```currentUser.Likes = append(...)... ```. I don't think thats where the issue lies, since running this code through the Goland debugger, the error seems to occur before it gets to this part of the function. The function for this method is shown below:
func (s *myService) UnlikeArtwork(ctx context.Context, req *pb.UnlikeArtworkRequest) (*pb.UnlikeArtworkResponse, error) {
currentUser, err := clients.Users.GetUser(ctx, &pbUsers.GetUserRequest{
Name: req.GetUser(),
ReadMask: &fieldmaskpb.FieldMask{Paths: []string{"likes"}},
})
if err != nil {
return nil, err
}
// Set new likes
//currentUser.Following = append(currentUser.Following[:sort.StringSlice(currentUser.Following).Search(req.GetUserToUnfollow())], currentUser.Following[sort.StringSlice(currentUser.Following).Search(req.GetUserToUnfollow())+1:]...)
currentUser.Likes = append(currentUser.Likes[:sort.StringSlice(currentUser.Likes).Search(req.GetUser())], currentUser.Likes[sort.StringSlice(currentUser.Likes).Search(req.GetUser())+1:]...)
// Update the current_user
_, err = clients.Users.UpdateUser(ctx, &pbUsers.UpdateUserRequest{
User: currentUser,
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"likes"}},
})
if err != nil {
return nil, err
}
currentArtwork, err := clients.Artworks.GetArtwork(ctx, &pbArtworks.GetArtworkRequest{
Name: req.GetArtworkToUnlike(),
ReadMask: &fieldmaskpb.FieldMask{Paths: []string{"likes"}},
})
if err != nil {
return nil, err
}
// Set the likes
//userToUnfollow.Followers = append(userToUnfollow.Followers[:sort.StringSlice(userToUnfollow.Followers).Search(req.GetCurrentUser())], userToUnfollow.Followers[sort.StringSlice(userToUnfollow.Followers).Search(req.GetCurrentUser())+1:]...)
currentArtwork.Likes = append(currentArtwork.Likes[:sort.StringSlice(currentArtwork.Likes).Search(req.GetArtworkToUnlike())], currentArtwork.Likes[sort.StringSlice(currentArtwork.Likes).Search(req.GetArtworkToUnlike())+1:]...)
// Update the current artwork
_, err = clients.Artworks.UpdateArtwork(ctx, &pbArtworks.UpdateArtworkRequest{
Artwork: currentArtwork,
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"likes"}},
})
if err != nil {
return nil, err
}
return &pb.UnlikeArtworkResponse{}, nil
}
The test was then run in a methods_test.go file where the inputs to the function and the function itself was simulated.
func TestMyService_UnlikeArtwork(t *testing.T) {
req := pbConsole.UnlikeArtworkRequest{
User: "PurpleRaine",
ArtworkToUnlike: "artworks/0cca6063-7b6f-464a-ac88-dff8679a3905",
}
// Run a method
res, err := client.UnlikeArtwork(context.Background(), &req)
if err != nil {
t.Error(err)
}
log.Println(logging.Entry{Message: res.String()})
}
The output of the test is:
methods_test.go:111: rpc error: code = Unavailable desc = error reading from server: EOF
methods_test.go:114: {"message":"\u003cnil\u003e","severity":"INFO"}
--- FAIL: TestMyService_UnLikeArtwork (0.01s)
FAIL
and this happens along with the server crash error listed at the beginning of this question.
**Additional Information:**
My user's server is configured as follows:
package main
import (
"context"
"fmt"
pb "github.com/jaebrownn/hockney/protobuf/go/hock/ap/resources/users/v1"
"google.golang.org/grpc"
"hock.ap.resources.users.v1/internal/logging"
"hock.ap.resources.users.v1/internal/methods"
"log"
"net"
"os"
)
// clients is a global clients, initialized once per cloud run instance.
var ()
func init() {
// Disable log prefixes such as the default timestamp.
// Prefix text prevents the message from being parsed as JSON.
// A timestamp is added when shipping logs to Cloud Logging.
log.SetFlags(0)
// TODO: implement when needed
// Ensure that required envs exist.
//if os.Getenv("ENV") == "" {
// log.Fatal("ENV env not set.")
//}
}
func main() {
log.Println(&logging.Entry{Message: "starting server...", Severity: logging.NOTICE})
port := os.Getenv("USERS_PORT")
if port == "" {
port = "8080"
log.Println(&logging.Entry{Message: "Defaulting to port " + port, Severity: logging.WARNING})
}
listener, err := net.Listen("tcp", ":"+port)
if err != nil {
log.Fatalf("net.Listen: %v", err)
}
grpcServer := grpc.NewServer(grpc.UnaryInterceptor(serverInterceptor))
pb.RegisterUsersServiceServer(grpcServer, &methods.MyService{})
if err = grpcServer.Serve(listener); err != nil {
log.Fatal(err)
}
}
// serverInterceptor is an example of a Server Interceptor which could be used to 'inject'
// for example logs and/or tracing details to incoming server requests.
// Add this method to your grpc server connection, for example
// grpcServer := grpc.NewServer(grpc.UnaryInterceptor(serverInterceptor))
//
// pb.RegisterServiceServer(grpcServer, &myService{})
func serverInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
// Calls the handler
h, err := handler(ctx, req)
if err != nil {
log.Println(&logging.Entry{Message: fmt.Sprintf("%v", req), Severity: logging.DEBUG, Ctx: ctx})
log.Println(&logging.Entry{Message: err.Error(), Severity: logging.WARNING, Ctx: ctx})
}
_ = info
return h, err
}
Edited: Here is the full stack trace when the crash occurs:
goroutine 54 [running]:
cloud.google.com/go/firestore.(*DocumentSnapshot).DataTo(0x0?, {0x104e28820?, 0x140000d02c0?})
/Users/michaelaltshuler/go/pkg/mod/cloud.google.com/go/firestore@v1.6.1/document.go:112 +0x24
hock.ap.resources.users.v1/internal/methods.(*MyService).GetUser(0x1400011f9a8?, {0x104e4ea60, 0x14000102750}, 0x14?)
/Users/michaelaltshuler/GolandProjects/hockney/products/hock/ap/resources/users/v1/internal/methods/methods.go:59 +0x84
github.com/jaebrownn/hockney/protobuf/go/hock/ap/resources/users/v1._UsersService_GetUser_Handler.func1({0x104e4ea60, 0x14000102750}, {0x104dd2d40?, 0x14000046340})
/Users/michaelaltshuler/GolandProjects/hockney/protobuf/go/hock/ap/resources/users/v1/users_grpc.pb.go:212 +0x74
main.serverInterceptor({0x104e4ea60?, 0x14000102750}, {0x104dd2d40, 0x14000046340}, 0x1400011faa8?, 0x104a98c24?)
/Users/michaelaltshuler/GolandProjects/hockney/products/hock/ap/resources/users/v1/server.go:62 +0x3c
github.com/jaebrownn/hockney/protobuf/go/hock/ap/resources/users/v1._UsersService_GetUser_Handler({0x104dd7cc0?, 0x1052cdd08}, {0x104e4ea60, 0x14000102750}, 0x14000140000, 0x104e44430)
/Users/michaelaltshuler/GolandProjects/hockney/protobuf/go/hock/ap/resources/users/v1/users_grpc.pb.go:214 +0x138
google.golang.org/grpc.(*Server).processUnaryRPC(0x140000d63c0, {0x104e52278, 0x14000003860}, 0x140005a4000, 0x140000a08a0, 0x10528e3f8, 0x0)
/Users/michaelaltshuler/go/pkg/mod/google.golang.org/grpc@v1.48.0/server.go:1295 +0x9c4
google.golang.org/grpc.(*Server).handleStream(0x140000d63c0, {0x104e52278, 0x14000003860}, 0x140005a4000, 0x0)
/Users/michaelaltshuler/go/pkg/mod/google.golang.org/grpc@v1.48.0/server.go:1636 +0x82c
google.golang.org/grpc.(*Server).serveStreams.func1.2()
/Users/michaelaltshuler/go/pkg/mod/google.golang.org/grpc@v1.48.0/server.go:932 +0x84
created by google.golang.org/grpc.(*Server).serveStreams.func1
/Users/michaelaltshuler/go/pkg/mod/google.golang.org/grpc@v1.48.0/server.go:930 +0x290
And when navigating to my getUser method from this stack trace it takes me to the line ```err = dsnap.DataTo(user)``` in the code below:
dsnap, err := clients.Firestore.Doc(req.GetName()).Get(ctx)
//user message to return
user := &pb.User{}
err = dsnap.DataTo(user) // This line
if err != nil {
return nil, err
}
I know this is a very long winded way of asking for help with this question. I have found very little resources online to deal with this issue, and I'm hoping this makes some sense and someone could guide me in the right direction.
Thank you!
</details>
# 答案1
**得分**: 1
我似乎已经解决了这个问题,而且比我最初想的要简单得多。在编写测试方法时,我将用户指定为```User: "UserID"```,然而,服务器期望的是一个指向 Firestore 文档引用的路径,并且需要输入```User: "user/UserID"```。
<details>
<summary>英文:</summary>
I seemed to have fixed the problem and it was a lot more simple than I originally thought. When writing the test method I was specifying the user as ```User: "UserID"```, however, the server expected a path to the firestore document ref, and needed the input ```User: "user/UserID"```.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论