Slide 1

Slide 1 text

Как не утонуть в ошибках Шихалеев Илья Ведущий инженер iSpring

Slide 2

Slide 2 text

Напишем простой handler загрузки файла ● Берем файл из запроса ● Создаем папку, куда хотим сохранить файл ● Создаем итоговый файл ● Записываем в итоговый файл данные из запроса 2

Slide 3

Slide 3 text

func uploadFile(w http.ResponseWriter, r *http.Request) { file, header := r.FormFile("file") 3

Slide 4

Slide 4 text

4

Slide 5

Slide 5 text

func uploadFile(w http.ResponseWriter, r *http.Request) { file, header, err := r.FormFile("file") if err != nil { http.Error(w, "Unable to read file", 400) return } 5

Slide 6

Slide 6 text

func uploadFile(w http.ResponseWriter, r *http.Request) { file, header, err := r.FormFile("file") if err != nil { http.Error(w, "Unable to read file", 400) return } os.MkdirAll("/path/", 0666) 6

Slide 7

Slide 7 text

7

Slide 8

Slide 8 text

func uploadFile(w http.ResponseWriter, r *http.Request) { file, header, err := r.FormFile("file") if err != nil { http.Error(w, "Unable to read file", 400) return } err = os.MkdirAll("/path/", 0666) if err != nil { http.Error(w, "Unable to create folder", 500) return } 8

Slide 9

Slide 9 text

resultFile := os.Create("/path/" + header.Filename) defer resultFile.Close() 9

Slide 10

Slide 10 text

10

Slide 11

Slide 11 text

resultFile, err := os.Create("/path/" + header.Filename) if err != nil { http.Error(w, err.Error(), 500) return } defer resultFile.Close() 11

Slide 12

Slide 12 text

resultFile, err := os.Create("/path/" + header.Filename) if err != nil { http.Error(w, err.Error(), 500) return } defer resultFile.Close() io.Copy(resultFile, file) 12

Slide 13

Slide 13 text

if err != nil

Slide 14

Slide 14 text

resultFile, err := os.Create("/path/" + header.Filename) if err != nil { http.Error(w, err.Error(), 500) return } defer resultFile.Close() _, err = io.Copy(resultFile, file) if err != nil { http.Error(w, err.Error(), 500) return } 14

Slide 15

Slide 15 text

func uploadFile(w http.ResponseWriter, r *http.Request) { file, header, err := r.FormFile("file") if err != nil { http.Error(w, "Unable to read file", 400) return } err = os.MkdirAll("/path/", 0666) if err != nil { http.Error(w, "Unable to create folder", 500) return } resultFile, err := os.Create("/path/" + header.Filename) if err != nil { http.Error(w, err.Error(), 500) return } defer resultFile.Close() _, err = io.Copy(resultFile, file) if err != nil { http.Error(w, err.Error(), 500) return } } 15

Slide 16

Slide 16 text

16

Slide 17

Slide 17 text

func uploadFile(w http.ResponseWriter, r *http.Request) { file, header := r.FormFile("file") os.MkdirAll("/path/", 0666) resultFile := os.Create("/path/" + header.Filename) defer resultFile.Close() io.Copy(resultFile, file) } 17

Slide 18

Slide 18 text

func uploadFile(w http.ResponseWriter, r *http.Request) { file, header := r.FormFile("file") os.MkdirAll("/path/", 0666) resultFile := os.Create("/path/" + header.Filename) defer resultFile.Close() io.Copy(resultFile, file) } if err != nil if err != nil if err != nil if err != nil if err != nil if err != nil if err != nil if err != nil if err != nil if err != nil 18

Slide 19

Slide 19 text

Как уменьшить дублирование и вернуться к написанию бизнес-логики? 19

Slide 20

Slide 20 text

Вариант 1 Решение из blog.golang.org 20

Slide 21

Slide 21 text

type appError struct { Error error Message string Code int } type appHandler func(http.ResponseWriter, *http.Request) *appError func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if e := fn(w, r); e != nil { http.Error(w, e.Message, e.Code) } } func init() { http.Handle("/upload", appHandler(uploadFile)) } 21

Slide 22

Slide 22 text

func uploadFile(w http.ResponseWriter, r *http.Request) *appError { file, header, err := r.FormFile("file") if err != nil { return &appError{err, "Unable to read file", 400} } err = os.MkdirAll("/path/", 0666) if err != nil { return &appError{err, "Unable to create folder", 500} } //... 22

Slide 23

Slide 23 text

Вариант 2 Решение от John Cinnamond 23

Slide 24

Slide 24 text

type uploader struct { err error } func (u *uploader) getFile(r *http.Request) (File, *FileHeader) { file, header, err := r.FormFile("file") return file, header } 24

Slide 25

Slide 25 text

type uploader struct { err error } func (u *uploader) getFile(r *http.Request) (File, *FileHeader) { if u.err != nil { return nil, nil } file, header, err := r.FormFile("file") if err != nil { u.err = errors.Wrap(err, "Unable to read file") } return file, header } 25

Slide 26

Slide 26 text

func (u *uploader) mkdir(uploadDir string) { if u.err != nil { return } err := os.MkdirAll(uploadDir, 0666) if err != nil { u.err = errors.Wrap(err, "Unable to create folder") } } func (u *uploader) copy(dst io.Writer, src io.Reader) { if u.err != nil { return } if _, err := io.Copy(dst, src); err != nil { u.err = err } } 26

Slide 27

Slide 27 text

func (u *uploader) createFile(filePath string) *os.File { if u.err != nil { return nil } resultFile, err := os.Create(filePath) if err != nil { u.err = err } return resultFile } 27

Slide 28

Slide 28 text

func uploadFile(w http.ResponseWriter, r *http.Request) { u := uploader{} file, header := u.getFile(r) u.mkdir("/path/") resultFile := u.createFile("/path/" + header.Filename) u.copy(resultFile, file) if u.err != nil { http.Error(w, fu.err.Error(), 500) return } } 28

Slide 29

Slide 29 text

Но как же избавиться от if err != nil? 29

Slide 30

Slide 30 text

Спасибо за внимание! 30

Slide 31

Slide 31 text

Полезные ссылки Немного про ошибки - https://golang.org/doc/effective_go.html#errors Обработка ошибок в блоге - https://blog.golang.org/error-handling-and-go Доклад John Cinnamond - https://youtu.be/1B71SL6Y0kA Пакет errors - https://golang.org/pkg/errors/ 31