Ответ
В Protobuf нет способа полностью запретить клиенту устанавливать значение поля, так как клиент может сформировать запрос с любыми данными. Однако есть несколько механизмов, чтобы сообщить о назначении поля и защитить сервер.
1. Опция deprecated
Это самый простой способ пометить поле как устаревшее. Он не запрещает использование, но может вызывать предупреждения при компиляции .proto
файлов в некоторых языках.
message MyRequest {
string public_field = 1;
// Поле только для внутреннего использования. Не используйте его.
string internal_field = 2 [deprecated = true];
}
2. Валидация на стороне сервера (самый надёжный способ)
Это единственный способ гарантированно предотвратить использование поля клиентом. Сервер должен проверять, что "внутреннее" поле не заполнено в запросе.
// Go-код на сервере
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func (s *Server) MyMethod(ctx context.Context, req *pb.MyRequest) (*pb.MyResponse, error) {
if req.GetInternalField() != "" {
return nil, status.Error(codes.InvalidArgument, "field 'internal_field' is for internal use only and must not be set by clients")
}
// ... остальная логика
return &pb.MyResponse{}, nil
}
3. Ключевое слово reserved
Если поле использовалось ранее, а теперь его нужно полностью убрать, но при этом не допустить его повторного использования с тем же номером (тегом) или именем, используется reserved
.
Это защищает от проблем обратной совместимости, когда старые клиенты могут по ошибке отправлять данные в поле, которое в новой версии схемы имеет другое назначение.
message MyRequest {
string public_field = 1;
reserved 2; // Номер тега 2 больше нельзя использовать
reserved "internal_field"; // Имя 'internal_field' больше нельзя использовать
}
Рекомендация: Лучшая практика — комбинировать подходы. Используйте комментарии в .proto
и опцию [deprecated = true]
для информирования разработчиков, но всегда реализуйте валидацию на стороне сервера для критически важных полей.