Upload
others
View
7
Download
0
Embed Size (px)
Citation preview
11
12
121
122
123
124
125
13
131
132
133
134
135
136
137
138
14
141
142
143
144
145
15
151
152
153
154
155
156
16
161
162
163
164
165
166
167
17
171
TableofContentsIntroduction
GoEnvironmentConfiguration
Installation
$GOPATHandworkspace
Gocommands
Godevelopmenttools
Summary
Gobasicknowledge
HelloGo
Gofoundation
Controlstatementsandfunctions
struct
Object-oriented
interface
Concurrency
Summary
Webfoundation
Webworkingprinciples
Buildasimplewebserver
HowGoworkswithweb
Getintohttppackage
Summary
HTTPForm
Processforminputs
Validationofinputs
Crosssitescripting
Duplicatesubmissions
Fileupload
Summary
Database
databasesqlinterface
HowtouseMySQL
HowtouseSQLite
HowtousePostgreSQL
HowtousebeedbORM
NOSQL
Summary
Datastorageandsession
Sessionandcookies
2
172
173
174
175
18
181
182
183
184
185
186
187
19
191
192
193
194
195
110
1101
1102
1103
1104
1105
1106
1107
111
1111
1112
1113
1114
112
1121
1122
1123
1124
113
1131
1132
1133
1134
1135
HowtousesessioninGo
Sessionstorage
Preventhijackofsession
Summary
Textfiles
XML
JSON
Regexp
Templates
Files
Strings
Summary
Webservices
Sockets
WebSocket
REST
RPC
Summary
Securityandencryption
CSRFattacks
Filterinputs
XSSattacks
SQLinjection
Passwordstorage
Encryptanddecryptdata
Summary
Internationalizationandlocalization
Timezone
Localizedresources
Internationalsites
Summary
Errorhandlingdebuggingandtesting
Errorhandling
DebuggingbyusingGDB
Writetestcases
Summary
Deploymentandmaintenance
Logs
Errorsandcrashes
Deployment
Backupandrecovery
Summary
3
114
1141
1142
1143
1144
1145
1146
115
1151
1152
1153
1154
1155
1156
1157
116
117
Buildawebframework
Projectprogram
Customizedrouters
Designcontrollers
Logsandconfigurations
Adddeleteandupdateblogs
Summary
Developwebframework
Staticfiles
Session
Form
Uservalidation
Multi-languagesupport
pprof
Summary
References
preface
4
BuildWebApplicationwithGolangPurpose
BecauseIminterestedinwebapplicationdevelopmentIusedmyfreetimetowritethisbookasanopensourceversionItdoesntmeanthatIhaveaverygoodabilitytobuildwebapplicationsIwouldliketosharewhatIvedonewithGoinbuildingwebapplications
ForthoseofyouwhoareworkingwithPHPPythonRubyyouwilllearnhowtobuildawebapplicationwithGoForthoseofyouwhoareworkingwithCC++youwillknowhowthewebworks
IbelievethepurposeofstudyingissharingwithothersThehappiestthinginmylifeissharingeverythingIveknownwithmorepeople
Donate
AliPay
alipay
EnglishDonatedonate
CommunityQQ群386056972
BBShttpgocnio
Acknowledgments四月份平民AprilCitizen(reviewcode)洪瑞琦HongRuiqi(reviewcode)边疆BianJiang(writetheconfigurationsaboutVimandEmacsforGodevelopment)欧林猫OlingCat(reviewcode)吴文磊WenleiWu(providesomepictures)北极星Polaris(reviewwholebook)雨痕RainTrail(reviewchapter2and3)
LicenseThisbookislicensedundertheCCBY-SA30LicensethecodeislicensedunderaBSD3-ClauseLicenseunlessotherwisespecified
GetStarted
Index
Introduction
5
Introduction
6
1GoEnvironmentConfigurationWelcometotheworldofGoletsstartexploring
Goisafast-compiledgarbage-collectedconcurrentsystemsprogramminglanguageIthasthefollowingadvantages
CompilesalargeprojectwithinafewsecondsProvidesasoftwaredevelopmentmodelthatiseasytoreasonaboutavoidingmostoftheproblemsassociatedwithC-styleheaderfilesIsastaticlanguagethatdoesnothavelevelsinitstypesystemsousersdonotneedtospendmuchtimedealingwithrelationsbetweentypesItismorelikealightweightobject-orientedlanguagePerformsgarbagecollectionItprovidesbasicsupportforconcurrencyandcommunicationDesignedformulti-corecomputers
GoisacompiledlanguageItcombinesthedevelopmentefficiencyofinterpretedordynamiclanguageswiththesecurityofstaticlanguagesItisgoingtobethelanguageofchoiceformodernmulti-corecomputerswithnetworkingForthesepurposestherearesomeproblemsthatneedtoinherentlyberesolvedatthelevelofthelanguageofchoicesuchasarichlyexpressivelightweighttypesystemanativeconcurrencymodelandstrictlyregulatedgarbagecollectionForquitesometimenopackagesortoolshaveemergedthathaveaimedtosolvealloftheseproblemsinapragmaticfashionthuswasbornthemotivationfortheGolanguage
InthischapterIwillshowyouhowtoinstallandconfigureyourownGodevelopmentenvironment
LinksDirectoryNextsectionInstallation
GoEnvironmentConfiguration
7
11Installation
ThreewaystoinstallGoTherearemanywaystoconfiguretheGodevelopmentenvironmentonyourcomputerandyoucanchoosewhicheveroneyoulikeThethreemostcommonwaysareasfollows
OfficialinstallationpackagesTheGoteamprovidesconvenientinstallationpackagesinWindowsLinuxMacandotheroperatingsystemsThisisprobablytheeasiestwaytogetstartedYoucangettheinstallersfromtheGolangDownloadPage
InstallityourselffromsourcecodePopularwithdeveloperswhoarefamiliarwithUnix-likesystems
Usingthird-partytoolsTherearemanythird-partytoolsandpackagemanagersforinstallingGolikeapt-getinUbuntuandhomebrewforMac
IncaseyouwanttoinstallmorethanoneversionofGoonacomputeryoushouldtakealookatatoolcalledGVMItisthebesttoolIveseensofarforaccomplishingthistaskotherwiseyoudhavetodealwithityourself
InstallfromsourcecodeTocompileGo15andupwardsyouonlyneedthepreviousversionofGoasGohasachievedbootstrappingYouonlyneedGotocompileGo
TocompileGo14downwardsyouwillneedaCcompilerassomepartsofGoarestillwritteninPlan9CandATampTassembler
OnaMacifyouhaveinstalledXcodeyoualreadyhavethecompiler
OnUnix-likesystemsyouneedtoinstallgccorasimilarcompilerForexampleusingthepackagemanagerapt-get(includedwithUbuntu)onecaninstalltherequiredcompilersasfollows
sudoapt-getinstallgcclibc6-dev
OnWindowsyouneedtoinstallMinGWinordertoinstallgccDontforgettoconfigureyourenvironmentvariablesaftertheinstallationhascompleted(EverythingthatlookslikethismeansitscommentedbyatranslatorIfyouareusing64-bitWindowsyoushouldinstallthe64-bitversionofMinGW)
AtthispointexecutethefollowingcommandstoclonetheGosourcecodeandcompileit(ItwillclonethesourcecodetoyourcurrentdirectorySwitchyourworkpathbeforeyoucontinueThismaytakesometime)
gitclonehttpsgogooglesourcecomgo
cdgosrc
allbash
AsuccessfulinstallationwillendwiththemessageALLTESTSPASSED
OnWindowsyoucanachievethesamebyrunningallbat
IfyouareusingWindowstheinstallationpackagewillsetyourenvironmentvariablesautomaticallyInUnix-likesystemsyouneedtosetthesevariablesmanuallyasfollows(IfyourGoversionisgreaterthan10youdonthavetoset$GOBINanditwillautomaticallyberelatedtoyour$GOROOTbinwhichwewilltalkaboutinthenextsection)
Installation
8
exportGOROOT=$HOMEgo
exportGOBIN=$GOROOTbin
exportPATH=$PATH$GOROOTbin
Ifyouseethefollowinginformationonyourscreenyoureallset
Figure11Informationafterinstallingfromsourcecode
OnceyouseetheusageinformationofGoitmeansyouhavesuccessfullyinstalledGoonyourcomputerIfitsaysnosuchcommandcheckthatyour$PATHenvironmentvariablecontainstheinstallationpathofGo
UsingthestandardinstallationpackagesGohasone-clickinstallationpackagesforeverysupportedoperatingsystemThesepackageswillinstallGoinusrlocalgo(cGoinWindows)bydefaultOfcoursethiscanbemodifiedbutyoualsoneedtochangealltheenvironmentvariablesmanuallyasIveshownabove
Howtocheckifyouroperatingsystemis32-bitor64-bit
Ournextstepdependsonyouroperatingsystemtypesowehavetocheckitbeforewedownloadthestandardinstallationpackages
IfyouareusingWindowspressWin+RandthenrunthecommandtoolTypethesysteminfocommandanditwillshowyousomeusefulsysteminformationFindthelinethatsayssystemtype-ifyouseex64-basedPCthatmeansyouroperatingsystemis64-bit32-bitotherwise
Istronglyrecommenddownloadingthe64-bitpackageifyouareaMacuserasGonolongersupportspure32-bitprocessorsonMacOSX
Linuxuserscantypeuname-aintheterminaltoseesysteminformationA64-bitoperatingsystemwillshowthefollowing
ltsomedescriptiongtx86_64x86_64x86_64GNULinux
somemachinessuchasUbuntu1004willshowasfollowing
x86_64GNULinux
32-bitoperatingsystemsinsteadshow
ltsomedescriptiongti686i686i386GNULinux
Mac
Gotothedownloadpagechoosego142darwin-386pkg(Thelaterversionhasno32-bitdownload)for32-bitsystemsandgo183darwin-amd64pkgfor64-bitsystemsGoingallthewaytotheendbyclickingnext~gobinwillbeaddedtoyoursystems$PATHafteryoufinishtheinstallationNowopentheterminalandtypegoYoushouldseethesameoutputshowninfigure11
Linux
Gotothedownloadpagechoosego183linux-386targzfor32-bitsystemsandgo183linux-amd64targzfor64-bitsystemsSupposeyouwanttoinstallGointhe$GO_INSTALL_DIRpathUncompressthetargztoyourchosenpathusingthecommandtarzxvfgo183linux-amd64targz-C$GO_INSTALL_DIRThensetyour$PATHwiththefollowingexportPATH=$PATH$GO_INSTALL_DIRgobinNowjustopentheterminalandtypegoYoushouldnowseethesameoutputdisplayedinfigure11
Installation
9
Windows
Gotothedownloadpagechoosego183windows-386msifor32-bitsystemsandgo183windows-amd64msifor64-bitsystemsGoingallthewaytotheendbyclickingnextcgobinwillbeaddedtopathNowjustopenacommandlinewindowandtypegoYoushouldnowseethesameoutputdisplayedinfigure11
Usethird-partytools
GVM
GVMisaGomulti-versioncontroltooldevelopedbyathird-partylikervmforrubyItsquiteeasytouseInstallgvmbytypingthefollowingcommandsinyourterminal
bashltlt(curl-s-S-Lhttpsrawgithubcommoovwebgvmmasterbinscriptsgvm-installer)
ThenweinstallGousingthefollowingcommands
gvminstallgo183
gvmusego183
Aftertheprocesshasfinishedyoureallset
apt-get
UbuntuisthemostpopulardesktopreleaseversionofLinuxItusesapt-gettomanagepackagesWecaninstallGousingthefollowingcommands
sudoadd-apt-repositoryppagophersgo
sudoapt-getupdate
sudoapt-getinstallgolang-go
wget
wgethttpsstoragegoogleapiscomgolanggo183linux-amd64targz
sudotar-xzfgo183linux-amd64targz-Cusrlocal
Goenvironment
exportGOROOT=usrlocalgo
exportGOBIN=$GOROOTbin
exportPATH=$PATH$GOBIN
exportGOPATH=$HOMEgopath
Startingfromgo18TheGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows
HomebrewHomebrewisasoftwaremanagementtoolcommonlyusedinMactomanagepackagesJusttypethefollowingcommandstoinstallGo
1 InstallHomebrew
usrbinruby-e$(curl-fsSLhttpsrawgithubusercontentcomHomebrewinstallmasterinstall)
Installation
10
1 InstallGo
brewupdateampampbrewupgrade
brewinstallgo
LinksDirectoryPrevioussectionGoenvironmentconfigurationNextsection$GOPATHandworkspace
Installation
11
12$GOPATHandworkspace
$GOPATHGotakesauniqueapproachtomanagethecodefileswiththeintroductionofa$GOPATHdirectorywhichcontainsallthegocodeinthemachineNotethatthisisdifferentfromthe$GOROOTenvironmentvariablewhichstateswheregoisinstalledonthemachineWehavetodefinethe$GOPATHvariablebeforeusingthelanguageinnixsystemsthereisafilecalledprofileweneedtoappendthebelowexportstatementtothefileTheconceptbehindgopathisanovelonewherewecanlinktoanygocodeatanyinstantoftimewithoutambiguity
Startingfromgo18theGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows
InUnix-likesystemsthevariableshouldbeusedlikethis
exportGOPATH=$HOMEmygo
InWindowsyouneedtocreateanewenvironmentvariablecalledGOPATHthensetitsvaluetocmygo(Thisvaluedependsonwhereyourworkspaceislocated)
ItsOKtohavemorethanonepath(workspace)in$GOPATHbutrememberthatyouhavetouse(inWindows)tobreakthemupAtthispointgogetwillsavethecontenttoyourfirstpathin$GOPATHItishighlyrecommendedtonothavemultiplesversionstheworstcaseistocreateafolderbythenameofyourprojectrightinside$GOPATHitbreakseverythingthatthecreatorswerewishingtochangeinprogrammingwiththecreationofgolanguagebecausewhenyoucreateafolderinside$GOPATHyouwillreferenceyourpackagesasdirectlyasandthisbreaksalltheapplicationswhichwillimportyourpackagebecausethegogetwontfindyourpackagePleasefollowconventionsthereisareasonconventionsarecreated
In$GOPATHyoumusthavethreefoldersasfollows
srcforsourcefileswhosesuffixisgocgspkgforcompiledfileswhosesuffixisabinforexecutablefiles
InthisbookIusemygoasmyonlypathin$GOPATH
PackagedirectoryCreatepackagesourcefilesandfolderslike$GOPATHsrcmymathsqrtgo(mymathisthepackagename)(Authorusesmymathashispackagenameandthesamenameforthefolderthatcontainsthepackagesourcefiles)
EverytimeyoucreateapackageyoushouldcreateanewfolderinthesrcdirectorywiththenotableexceptionofmainforwhichmainfoldercreationisoptionalFoldernamesareusuallythesameasthepackagethatyouaregoingtouseYoucanhavemulti-leveldirectoriesifyouwanttoForexampleifyoucreatethedirectory$GOPATHsrcgithubcomastaxiebeedbthenthepackagepathwouldbegithubcomastaxiebeedbThepackagenamewillbethelastdirectoryinyourpathwhichisbeedbinthiscase
Executefollowingcommands(Nowauthorgoesbacktotalkexamples)
cd$GOPATHsrc
mkdirmymath
Createanewfilecalledsqrtgotypethefollowingcontenttoyourfile
$GOPATHandworkspace
12
Sourcecodeof$GOPATHsrcmymathsqrtgo
packagemymath
funcSqrt(xfloat64)float64
z=00
fori=0ilt1000i++
z-=(zz-x)(2x)
returnz
NowmypackagedirectoryhasbeencreatedanditscodehasbeenwrittenIrecommendthatyouusethesamenameforyourpackagesastheircorrespondingdirectoriesandthatthedirectoriescontainallofthepackagesourcefiles
CompilepackagesWevealreadycreatedourpackageabovebuthowdowecompileitforpracticalpurposesTherearetwowaystodothis
1 Switchyourworkpathtothedirectoryofyourpackagethenexecutethegoinstallcommand2 Executetheabovecommandexceptwithafilenamelikegoinstallmymath
Aftercompilingwecanopenthefollowingfolder
cd$GOPATHpkg$GOOS_$GOARCH
youcanseethefilewasgenerated
mymatha
ThefilewhosesuffixisaisthebinaryfileofourpackageHowdoweuseit
Obviouslyweneedtocreateanewapplicationtouseit
Createanewapplicationpackagecalledmathapp
cd$GOPATHsrc
mkdirmathapp
cdmathapp
vimmaingo
Writethefollowingcontenttomaingo
$GOPATHsrcmathappmaingosourcecode
packagemain
import(
mymath
fmt
)
funcmain()
fmtPrintf(HelloworldSqrt(2)=vnmymathSqrt(2))
Tocompilethisapplicationyouneedtoswitchtotheapplicationdirectorywhichinthiscaseis$GOPATHsrcmathappthenexecutethegoinstallcommandNowyoushouldseeanexecutablefilecalledmathappwasgeneratedinthedirectory$GOPATHbinTorunthisprogramusethemathappcommandYoushouldseethefollowingcontentinyourterminal
HelloworldSqrt(2)=1414213562373095
$GOPATHandworkspace
13
InstallremotepackagesGohasatoolforinstallingremotepackageswhichisacommandcalledgogetItsupportsmostopensourcecommunitiesincludingGithubGoogleCodeBitBucketandLaunchpad
gogetgithubcomastaxiebeedb
Youcanusegoget-uhelliptoupdateyourremotepackagesanditwillautomaticallyinstallallthedependentpackagesaswell
ThistoolwillusedifferentversioncontroltoolsfordifferentopensourceplatformsForexamplegitforGithubandhgforGoogleCodeThereforeyouhavetoinstalltheseversioncontroltoolsbeforeyouusegoget
Afterexecutingtheabovecommandsthedirectorystructureshouldlooklikefollowing
$GOPATH
src
|-githubcom
|-astaxie
|-beedb
pkg
|--$GOOS_$GOARCH
|-githubcom
|-astaxie
|-beedba
Actuallygogetclonessourcecodetothe$GOPATHsrcofthelocalfilesystemthenexecutesgoinstall
Youcanuseremotepackagesinthesamewaythatweuselocalpackages
importgithubcomastaxiebeedb
DirectorycompletestructureIfyouvefollowedalloftheabovestepsyourdirectorystructureshouldnowlooklikethefollowing
bin
mathapp
pkg
$GOOS_$GOARCHsuchasdarwin_amd64linux_amd64
mymatha
githubcom
astaxie
beedba
src
mathapp
maingo
mymath
sqrtgo
githubcom
astaxie
beedb
beedbgo
utilgo
Nowyouareabletoseethedirectorystructureclearlybincontainsexecutablefilespkgcontainscompiledfilesandsrccontainspackagesourcefiles
(TheformatofenvironmentvariablesinWindowsisGOPATHhoweverthisbookmainlyfollowstheUnix-stylesoWindowsusersneedtoreplacetheseyourself)
$GOPATHandworkspace
14
LinksDirectoryPrevioussectionInstallationNextsectionGocommands
$GOPATHandworkspace
15
13Gocommands
GocommandsTheGolanguagecomeswithacompletesetofcommandoperationtoolsYoucanexecutethegocommandontheterminaltoseethem
Figure13Gocommanddisplaysdetailedinformation
TheseareallusefulforusLetsseehowtousesomeofthem
gobuildThiscommandisforcompilingtestsItwillcompilepackagesanddependenciesifitsnecessary
Ifthepackageisnotthemainpackagesuchasmymathinsection12nothingwillbegeneratedafteryouexecutegobuildIfyouneedthepackagefileain$GOPATHpkgusegoinstallinsteadIfthepackageisthemainpackageitwillgenerateanexecutablefileinthesamefolderIfyouwantthefiletobegeneratedin$GOPATHbinusegoinstallorgobuild-o$PATH_HEREaexeIftherearemanyfilesinthefolderbutyoujustwanttocompileoneofthemyoushouldappendthefilenameaftergobuildForexamplegobuildagogobuildwillcompileallthefilesinthefolderYoucanalsoassignthenameofthefilethatwillbegeneratedForinstanceinthemathappproject(insection12)usinggobuild-oastaxieexewillgenerateastaxieexeinsteadofmathappexeThedefaultnameisyourfoldername(non-mainpackage)orthefirstsourcefilename(mainpackage)
(AccordingtoTheGoProgrammingLanguageSpecificationpackagenamesshouldbethenameafterthewordpackageinthefirstlineofyoursourcefilesItdoesnthavetobethesameasthefoldernameandtheexecutablefilenamewillbeyourfoldernamebydefault)
gobuildignoresfileswhosenamesstartwith_orIfyouwanttohavedifferentsourcefilesforeveryoperatingsystemyoucannamefileswiththesystemnameasasuffixSupposetherearesomesourcefilesforloadingarraysTheycouldbenamedasfollows
array_linuxgo|array_darwingo|array_windowsgo|array_freebsdgo
gobuildchoosestheonethatsassociatedwithyouroperatingsystemForexampleitonlycompilesarray_linuxgoinLinuxsystemsandignoresalltheothers
gocleanThiscommandisforcleaningfilesthataregeneratedbycompilersincludingthefollowingfiles
_objolddirectoryofobjectleftbyMakefiles
_testolddirectoryoftestleftbyMakefiles
_testmaingoolddirectoryofgotestleftbyMakefiles
testoutolddirectoryoftestleftbyMakefiles
buildoutolddirectoryoftestleftbyMakefiles
[568ao]objectfilesleftbyMakefiles
DIR(exe)generatedbygobuild
DIRtest(exe)generatedbygotest-c
MAINFILE(exe)generatedbygobuildMAINFILEgo
Gocommands
16
IusuallyusethiscommandtocleanupmyfilesbeforeIuploadmyprojecttoGithubTheseareusefulforlocaltestsbutuselessforversioncontrol
gofmtandgofmtThepeoplewhoareworkingwithCC++shouldknowthatpeoplearealwaysarguingaboutwhichcodestyleisbetterKampR-styleorANSI-styleHoweverinGothereisonlyonecodestylewhichisenforcedForexampleleftbracesmustonlybeinsertedattheendoflinesandtheycannotbeontheirownlinesotherwiseyouwillgetcompileerrorsFortunatelyyoudonthavetoremembertheserulesgofmtdoesthisjobforyouJustexecutethecommandgofmtltFilenamegtgointerminalIdontusethiscommandverymuchbecauseIDEsusuallyexecutethiscommandautomaticallywhenyousavesourcefilesIwilltalkmoreaboutIDEsinthenextsection
gofmtisjustanaliaswhichrunsthecommandgofmt-l-wonthepackagesnamedbytheimportpaths
Weusuallyusegofmt-winsteadofgofmtThelatterwillnotrewriteyoursourcefilesafterformattingcodegofmt-wsrcformatsthewholeproject
gogetThiscommandisforgettingremotepackagesSofaritsupportsBitBucketGithubGoogleCodeandLaunchpadThereareactuallytwothingsthathappenafterweexecutethiscommandThefirstthingisthatGodownloadsthesourcecodethenexecutesgoinstallBeforeyouusethiscommandmakesureyouhaveinstalledalloftherelatedtools
BitBucket(MercurialGit)
Github(git)
GoogleCode(GitMercurialSubversion)
Launchpad(Bazaar)
InordertousethiscommandyouhavetoinstallthesetoolscorrectlyDontforgettoupdatethe$PATHvariableBythewayitalsosupportscustomizeddomainnamesUsegohelpimportpathformoredetailsaboutthis
goinstallThiscommandcompilesallpackagesandgeneratesfilesthenmovesthemto$GOPATHpkgor$GOPATHbin
gotestThiscommandloadsallfileswhosenameinclude_testgoandgeneratestestfilesthenprintsinformationthatlookslikethefollowing
okarchivetar0011s
FAILarchivezip0022s
okcompressgzip0033s
IttestsallyourtestfilesbydefaultUsecommandgohelptestflagformoredetails
godocManypeoplesaythatwedontneedanythird-partydocumentationforprogramminginGo(actuallyIvemadeaCHMalready)Gohasapowerfultooltomanagedocumentationnatively
Gocommands
17
SohowdowelookuppackageinformationindocumentationForinstanceifyouwanttogetmoredetailsaboutthebuiltinpackageusethegodocbuiltincommandSimilarlyusethegodocnethttpcommandtolookupthehttppackagedocumentationIfyouwanttoseemoredetailsaboutspecificfunctionsusethegodocfmtPrintfandgodoc-srcfmtPrintfcommandstoviewthesourcecode
Executethegodoc-http=8080commandthenopen1270018080inyourbrowserYoushouldseealocalizedgolangorgItcannotonlyshowthestandardpackagesinformationbutalsopackagesinyour$GOPATHpkgItsgreatforpeoplewhoaresufferingfromtheGreatFirewallofChina
OthercommandsGoprovidesmorecommandsthanthosewevejusttalkedabout
gofixupgradecodefromanoldversionbeforego1toanewversionaftergo1
goversiongetinformationaboutyourversionofGo
goenvviewenvironmentvariablesaboutGo
golistlistallinstalledpackages
goruncompiletemporaryfilesandruntheapplication
TherearealsomoredetailsaboutthecommandsthatIvetalkedaboutYoucanusegohelpltcommandgttolookthemup
LinksDirectoryPrevioussection$GOPATHandworkspaceNextsectionGodevelopmenttools
Gocommands
18
GodevelopmenttoolsInthissectionImgoingtoshowyouafewIDEsthatcanhelpyoubecomeamoreefficientprogrammerwithcapabilitiessuchasintelligentcodecompletionandauto-formattingTheyareallcross-platformsothestepsIwillbeshowingyoushouldnotbeverydifferentevenifyouarenotusingthesameoperatingsystem
LiteIDELiteIDEisanopensourcelightweightIDEfordevelopingGoprojectsonlydevelopedbyvisualfc
Figure14MainpanelofLiteIDE
LiteIDEfeatures
Cross-platformWindowsLinuxMacOS
Cross-compileManagemultiplecompileenvironmentsSupportscross-compilationofGo
ProjectmanagementstandardDocumentationviewbasedon$GOPATHCompilationsystembasedon$GOPATHAPIdocumentationindexbasedon$GOPATH
GosourcecodeeditorCodeoutliningFullsupportofgocodeGodocumentationviewandAPIindexViewcodeexpressionusingF1FunctiondeclarationjumpusingF2GdbsupportAuto-formatwithgofmt
OthersMulti-languagePluginsystemTexteditorthemesSyntaxsupportbasedonKateintelligentcompletionbasedonfull-textCustomizedshortcutsMarkdownsupport
Real-timepreviewCustomizedCSSExportHTMLandPDFConvertandmergetoHTMLandPDF
LiteIDEinstallationInstallLiteIDE
Downloadpage
Godevelopmenttools
19
Sourcecode
YouneedtoinstallGofirstthendownloadtheversionappropriateforyouroperatingsystemDecompressthepackagetodirectlyuseit
Installgocode
Youhavetoinstallgocodeinordertouseintelligentcompletion
goget-ugithubcomnsfgocode
Compilationenvironment
SwitchconfigurationinLiteIDEtosuityouroperatingsystemInWindowsandusingthe64-bitversionofGoyoushouldchoosewin64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenfilewin64envintherightlist
GOROOT=cgo
GOBIN=
GOARCH=amd64
GOOS=windows
CGO_ENABLED=1
PATH=GOBINGOROOTbinPATH
ReplaceGOROOT=cgotoyourGoinstallationpathsaveitIfyouhaveMinGW64addcMinGW64bintoyourpathenvironmentvariableforcgosupport
InLinuxandusingthe64-bitversionofGoyoushouldchooselinux64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenthelinux64envfileintherightlist
GOROOT=$HOMEgo
GOBIN=
GOARCH=amd64
GOOS=linux
CGO_ENABLED=1
PATH=$GOBIN$GOROOTbin$PATH
ReplaceGOROOT=$HOMEgotoyourGoinstallationpathsaveit
$GOPATH$GOPATHisthepaththatcontainsalistofprojectsOpenthecommandtool(orpressCtrl+`inLiteIDE)thentypegohelpgopathformoredetailsItsveryeasytoviewandchange$GOPATHinLiteIDEFollowView-SetupGOPATHtoviewandchangethesevalues
SublimeTextHereImgoingtointroduceyoutheSublimeText3(Sublimeforshort)+GoSublime+gocodeLetmeexplainwhy
Intelligentcompletion
Figure15Sublimeintelligentcompletion
Auto-formatsourcefilesProjectmanagement
Godevelopmenttools
20
Figure16Sublimeprojectmanagement
Syntaxhighlight
FreetrialforeverwithnofunctionallimitationsYoumaybepromptedonceinawhiletoremindyoutopurchasealicensebutyoucansimplyignoreitifyouwishOfcourseifyoudofindthatitenhancesyourproductivityandyoureallyenjoyusingitpleasepurchaseacopyofitandsupportitscontinueddevelopment
FirstdownloadtheversionofSublimesuitableforyouroperatingsystem
1 PressCtrl+`openthecommandtoolandinputthefollowingcommands
ApplicabletoSublimeText3
importurllibrequestospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()urllibrequesti
nstall_opener(urllibrequestbuild_opener(urllibrequestProxyHandler()))open(ospathjoin(ipppf)wb)write(urlli
brequesturlopen(httpsublimewbondnet+pfreplace(20))read())
ApplicabletoSublimeText2
importurllib2ospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()osmakedirs(ipp)ifnotos
pathexists(ipp)elseNoneurllib2install_opener(urllib2build_opener(urllib2ProxyHandler()))open(ospathjoin(ipp
pf)wb)write(urllib2urlopen(httpsublimewbondnet+pfreplace(20))read())print(PleaserestartSubl
imeTexttofinishinstallation)
RestartSublimeTextwhentheinstallationhasfinishedYoushouldthenfinda`PackageControl`optioninthePref
erencesmenu
[](images14sublime3pngraw=true)
Figure17SublimePackageControl
1 ToinstallGoSublimeSidebarEnhancementsandGoBuildpressCtrl+Shift+ptoopenPackageControlthentypepcip(shortforPackageControlInstallPackage)
Figure18SublimeInstallPackages
NowtypeinGoSublimepressOKtoinstallthepackageandrepeatthesamestepsforinstallingSidebarEnhancementsandGoBuildOnceagainrestarttheeditorwhenitcompletestheinstallation
2 ToverifythattheinstallationissuccessfulopenSublimethenopenthemaingofiletoseeifithasthepropersyntaxhighlightingTypeimporttoseeifcodecompletionpromptsappearAftertypingimportfmttypefmtanywhereaftertheimportdeclarationtoseewhetherornotintelligentcodecompletionforfunctionswassuccessfullyenabled
Ifeverythingisfineyoureallset
Ifnotcheckyour$PATHagainOpenaterminaltypegocodeIfitdoesnotrunyour$PATHwasnotconfiguredcorrectly
VimVimisapopulartexteditorforprogrammerswhichevolvedfromitsslimmerpredecessorViIthasfunctionsforintelligentcompletioncompilationandjumpingtoerrors
vim-goisvimaboveanopen-sourcegolanguageusingthemostextensivedevelopmentenvironmentplug-ins
Thepluginaddressgithubcomfatihvim-go
Godevelopmenttools
21
VimpluginmanagementarethemainstreamPathogenandVundleButtheaspectsthereofaredifferentPathogenistosolveeachplug-inaftertheinstallationoffilesscatteredtomultipledirectoriesandpoormanagementoftheexistenceVundleistosolvetheautomaticsearchanddownloadplug-insexistThesetwoplug-inscanbeusedsimultaneously
1InstallVundle
mkdir~vimbundle
gitclonehttpsgithubcomgmarikVundlevimgit~vimbundleVundlevim
EditvimrcVundletherelevantconfigurationwillbeplacedinthebeginning(RefertotheVundledocumentationfordetails)
setnocompatiblebeiMprovedrequired
filetypeoffrequired
settheruntimepathtoincludeVundleandinitialize
setrtp+=~vimbundleVundlevim
callvundlebegin()
letVundlemanageVundlerequired
PlugingmarikVundlevim
AllofyourPluginsmustbeaddedbeforethefollowingline
callvundleend()required
filetypepluginindentonrequired
2InstallVim-go
Edit~vimrcAddalinebetweenvundlebeginandvundleend
Pluginfatihvim-go
ExecutedwithinVimPluginInstall
3InstallYCM(YourCompleteMe)toAutoCompleteAddalineto~vimrc
PluginValloricYouCompleteMe
ExecutedwithinVimPluginInstall
Figure18VimintelligentcompletionforGo
1 SyntaxhighlightingforGo
cp-r$GOROOTmiscvim~vim
2 Enablingsyntaxhighlighting
filetypepluginindenton
syntaxon
3 Installgocode
goget-ugithubcomnsfgocode
gocodewillbeinstalledin$GOBINasdefault
Godevelopmenttools
22
4 Configuregocode
~cd$GOPATHsrcgithubcomnsfgocodevim
~updatesh
~gocodesetpropose-builtinstrue
propose-builtinstrue
~gocodesetlib-pathhomebordergocodepkglinux_amd64
lib-pathhomebordergocodepkglinux_amd64
~gocodeset
propose-builtinstrue
lib-pathhomebordergocodepkglinux_amd64
Explanationofgocodeconfiguration
propose-builtinsspecifieswhetherornottoopenintelligentcompletionfalsebydefaultlib-pathgocodeonlysearchesforpackagesin$GOPATHpkg$GOOS_$GOARCHand$GOROOTpkg$GOOS_$GOARCHThissettingcanbeusedtoaddadditionalpaths
5 CongratulationsTryemaingotoexperiencetheworldofGo
EmacsEmacsistheso-calledWeaponofGodSheisnotonlyaneditorbutalsoapowerfulIDE
Figure110EmacsmainpanelofGoeditor
1 Syntaxhighlighting
cp$GOROOTmiscemacs~emacsd
2 Installgocode
goget-ugithubcomnsfgocode
gocodewillbeinstalledin$GOBINasdefault
3 Configuregocode
~cd$GOPATHsrcgithubcomnsfgocodevim
~updatebash
~gocodesetpropose-builtinstrue
propose-builtinstrue
~gocodesetlib-pathhomebordergocodepkglinux_amd64
lib-pathhomebordergocodepkglinux_amd64
~gocodeset
propose-builtinstrue
lib-pathhomebordergocodepkglinux_amd64
4 InstallAutoCompletionDownloadanduncompress
~makeinstallDIR=$HOMEemacsdauto-complete
Configure~emacsfile
Godevelopmenttools
23
auto-complete
(requireauto-complete-config)
(add-to-listac-dictionary-directories~emacsdauto-completeac-dict)
(ac-config-default)
(local-set-key(kbdM-)semantic-complete-analyze-inline)
(local-set-keysemantic-complete-self-insert)
(local-set-keygtsemantic-complete-self-insert)
Followthislinkformoredetails
5 Configureemacs
golangmode
(requirego-mode-load)
(requirego-autocomplete)
speedbar
(speedbar1)
(speedbar-add-supported-extensiongo)
(add-hook
go-mode-hook
(lambda()
gocode
(auto-complete-mode1)
(setqac-sources(ac-source-go))
ImenuampSpeedbar
(setqimenu-generic-expression
((type^type([^tnrf])1)
(func^func()1)))
(imenu-add-to-menubarIndex)
Outlinemode
(make-local-variableoutline-regexp)
(setqoutline-regexp|[^rnf][^rnf]|pack|func|impo|cons|var|type|tt)
(outline-minor-mode1)
(local-set-keyM-aoutline-previous-visible-heading)
(local-set-keyM-eoutline-next-visible-heading)
Menubar
(requireeasymenu)
(defconstgo-hooked-menu
(Gotools
[Gorunbuffergot]
[Goreformatbuffergo-fmt-buffert]
[Gocheckbuffergo-fix-buffert]))
(easy-menu-define
go-added-menu
(current-local-map)
Gotools
go-hooked-menu)
Other
(setqshow-trailing-whitespacet)
))
helperfunction
(defungo()
runcurrentbuffer
(interactive)
(compile(concatgorun(buffer-file-name))))
helperfunction
(defungo-fmt-buffer()
rungofmtoncurrentbuffer
(interactive)
(ifbuffer-read-only
(progn
(ding)
(messageBufferisreadonly))
(let((p(line-number-at-pos))
(filename(buffer-file-name))
(old-max-mini-window-heightmax-mini-window-height))
(show-all)
(if(get-bufferGoReformatErrors)
Godevelopmenttools
24
(progn
(delete-windows-onGoReformatErrors)
(kill-bufferGoReformatErrors)))
(setqmax-mini-window-height1)
(if(=0(shell-command-on-region(point-min)(point-max)gofmtGoReformatOutputnilGoRefor
matErrorst))
(progn
(erase-buffer)
(insert-buffer-substringGoReformatOutput)
(goto-char(point-min))
(forward-line(1-p)))
(with-current-bufferGoReformatErrors
(progn
(goto-char(point-min))
(while(re-search-forwardltstandardinputgtnilt)
(replace-matchfilename))
(goto-char(point-min))
(compilation-mode))))
(setqmax-mini-window-heightold-max-mini-window-height)
(delete-windows-onGoReformatOutput)
(kill-bufferGoReformatOutput))))
helperfunction
(defungo-fix-buffer()
rungofixoncurrentbuffer
(interactive)
(show-all)
(shell-command-on-region(point-min)(point-max)gotoolfix-diff))
6 CongratulationsyouredoneSpeedbarisclosedbydefault-removethecommentsymbolsintheline(speedbar1)toenablethisfeatureoryoucanuseitthroughM-xspeedbar
EclipseEclipseisalsoagreatdevelopmenttoolIllshowyouhowtouseittowriteGoprograms
Figure11EclipsemainpanelforeditingGo
1 DownloadandinstallEclipse2 DownloadgoclipsehttpcodegooglecompgoclipsewikiInstallationInstructions3 Downloadgocode
gocodeinGithub
httpsgithubcomnsfgocode
YouneedtoinstallgitinWindowsusuallyweusemsysgit
Installgocodeinthecommandtool
goget-ugithubcomnsfgocode
Youcaninstallfromsourcecodeifyoulike
4 DownloadandinstallMinGW5 Configureplugins
Windows-gtPreferences-gtGo
(1)ConfigureGocompiler
Godevelopmenttools
25
Figure112GoSettinginEclipse
(2)Configuregocode(optional)setgocodepathtowherethegocodeexeis
Figure113gocodeSetting
(3)Configuregdb(optional)setgdbpathtowherethegdbexeis
Figure114gdbSetting
6 Checktheinstallation
CreateanewGoprojectandhellogofileasfollowing
Figure115Createanewprojectandfile
Testinstallationasfollows(youneedtotypecommandinconsoleinEclipse)
Figure116TestGoprograminEclipse
IntelliJIDEAPeoplewhohaveworkedwithJavashouldbefamiliarwiththisIDEItsupportsGosyntaxhighlightingandintelligentcodecompletionimplementedbyaplugin
1 DownloadIDEAthereisnodifferencebetweentheUltimateandCommunityeditions
2 InstalltheGopluginChooseFile-Setting-PluginsthenclickBrowserrepo
3 Searchgolangdoubleclickdownloadandinstallandwaitforthedownloadtocomplete
ClickApplythenrestart
4 NowyoucancreateaGoproject
InputthepositionofyourGosdkinthenextstep-basicallyitsyour$GOROOT
(SeeablogpostforsetupanduseIntelliJIDEAwithGostepbystep)
VisualStudioVSCodeThisisanawesometexteditorreleasedasopensourcecrossplatformmyMicrosoftwhichtakesthedevelopmentexperiencetoawholenewlevelhttpscodevisualstudiocomIthaseverythingamoderntexteditorisexpectedtohaveanddespitebeingbasedonthesamebackendthatatomioisbaseditisveryfast
ItworkswithWindowsMacLinuxIthasgopackagebuiltitprovidescodelinting
Godevelopmenttools
26
AtomAtomisanawesometexteditorreleasedasopensourcecrossplatformbuiltonElectronandbasedoneverythingweloveaboutourfavoriteeditorsWedesignedittobedeeplycustomizablebutstillapproachableusingthedefaultconfiguration
Downloadhttpsatomio
GoglandGoglandisthecodenameforanewcommercialIDEbyJetBrainsaimedatprovidinganergonomicenvironmentforGodevelopment
Theofficialversionisnotyetreleased
Downloadhttpswwwjetbrainscomgo
LinksDirectoryPrevioussectionGocommandsNextsectionSummary
Godevelopmenttools
27
15SummaryInthischapterwetalkedabouthowtoinstallGousingthreedifferentmethodsincludingfromsourcecodethestandardpackageandviathird-partytoolsThenweshowedyouhowtoconfiguretheGodevelopmentenvironmentmainlycoveringhowtosetupyour$GOPATHAfterthatweintroducedsomestepsforcompilinganddeployingGoprogramsWethencoveredGocommandsincludingthecompileinstallformatandtestcommandsFinallytherearemanypowerfultoolstodevelopGoprogramssuchasLiteIDESublimeTextVSCodeAtomGoglangVimEmacsEclipseIntelliJIDEAetcYoucanchooseanyoneyoulikeexploringtheworldofGo
LinksDirectoryPrevioussectionGodevelopmenttoolsNextchapterGobasicknowledge
Summary
28
2GobasicknowledgeGoisacompiledsystemprogramminglanguageanditbelongstotheC-familyHoweveritscompilationspeedismuchfasterthanotherC-familylanguagesIthasonly25keywordsevenlessthanthe26lettersoftheEnglishalphabetLetstakealookatthesekeywordsbeforewegetstarted
breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar
InthischapterImgoingtoteachyousomebasicGoknowledgeYouwillfindouthowconcisetheGoprogramminglanguageisandthebeautifuldesignofthelanguageProgrammingcanbeveryfuninGoAfterwecompletethischapteryoullbefamiliarwiththeabovekeywords
LinksDirectoryPreviouschapterChapter1SummaryNextsectionHelloGo
Gobasicknowledge
29
WhatmakesGodifferentfromotherlanguagesTheGoprogramminglanguagewascreatedwithonegoalinmindtobeabletobuildscalableweb-applicationsforlargescaleaudiencesinalargeteamSothatisthereasontheymadethelanguageasstandardizedaspossiblehencethegofmttoolandthestrictusageguidelinestothelanguagewasforthesakeofnothavingtwofactionsinthedeveloperbaseinotherlanguagestherearereligiouswarsonwheretokeeptheopeningbrace
publicstaticvoidmain()
or
publicstaticvoidmain()
orforpythonshouldweuse4spacesor6spacesoratabortwotabsandotheruserpreferencesIfyouknowpythonthenyoumightbeawareofPEP8whichisasetofguidelinesabouthowtowriteelegantcode
WhilethismightseemtobeashallowproblemwhenthecodebasegrowsandmoreandmorepeopleworkonthesamecodebaseitisbecomesincreasinglydifficulttomaintainthecodesbeautyWeliveinaworldwhererobotscandriveacarsoweshouldntjustwritecodeweshouldwriteelegantcode
ForotherlanguagestherearemanyvariableswhenitcomestowritingcodeEverylanguageisgoodforitsusecasebutGoisalittlespecialbecauseitwasdesignedatacompanywhichistheverysynonymoftheInternet(anddistributedcomputing)TypicallyinordertooptimizeprogramsdeveloperschoosetowriteJavaoverPythonandC++overJavabutalmostallavailablelanguageswidelyinusewerewrittendecadesagowhen1GBstoragewasmuchpricierNowstorageandcomputingisrelativelycheapandcomputersaregettingmultiplescoresbuttheoldlanguagesarenotharnessingconcurrencyinawaythatgodoesItsnotbecausethoselanguagesarebadutilizingconcurrencywasntarelevantusecasewhiletheolderlanguagesevolved
TomitigatealltheproblemsthatGooglefacedwithcurrenttoolstheywroteasystemslanguagecalledGowhichyouareabouttolearnTherearemanyadvantagestousinggolangandtherearedisadvantagestooforeverycoinhasbothsidesOneofthesignificantimprovementsinincodeformattingGooglehasdesignedthelanguagetoavoiddebatesoncodeformattingGocodewrittenbyanyoneintheworld(assumingtheyknowandusegofmt)willlookexactlythesameThiswontseemtomatteruntilyouworkinateamAlsowhenthecompanyusesautomatedcoderevieworsomeotherfancytechniquetheformattedcodemaybreakinotherlanguageswhichdonthavestrictandstandardformattingrulesbutnotingo
Gowasdesignedwithconcurrencyinmindpleasenotethatparallelism=concurrencythereisanamazingpostbyRobPikeonthegolangblogyouwillfinditthereitiswortharead
AnotherveryimportantchangethatistheconceptofGOPATHGonearethedayswhenyouhadtocreateafoldercalledcodeandthencreateworkspacesforeclipseandwhatnotNowyouhavetokeeponefoldertreeforgocodewhichwillbeupdatedbythepackagemanagerautomaticallyItisalsorecommendedtocreatefolderswitheitheracustomdomainorthegithubdomainforexampleIcreatedataskmanagerusinggolangsoIcreatedasetoffolders~gosrcgithubcomthewhitetulipTasks
NoteInnixsystems~standsforhomedirectorywhichisthewindowsequivalentofCUsersusernameNowthe~goistheuniverseforthegocodeinyourmachineThisisasignificantimprovementoverotherlanguageswecanstorethecodeefficientlywithouthasslesWhileitmightseemstrangeatfirstthisapproachmakealotofsensethantheridiculouspackagenamesiepackagenamesgeneratedforotherlanguagesusingreversedomains
NoteAlongwithsrctherearetwofolderspkgwhichisforpackagesandbinwhichisforbinary
HelloGo
30
ThisGOPATHadvantageisntjustrestrictedtostoringcodeinparticularfolderWhenyouhavecreatedfivepackagesforyourprojectyoudonthavetoimportthemlikeimportdbInsteadyoucanuseimportgithubcomthewhitetulipTasksdbsothatwhenexecutinggogetonmyrepothegotoolwillfindthepackagefromgithubcompathifitwasntdownloadedinitiallyThisstandardizesalotofscrewedupthingsintheprogrammingdiscipline(lt--Toremoveandreplacewithactualexplanationofwhythisisbetter)
Whiletheremaybesomefoundedcomplaintsthatgocreatorshaveignoredalllanguageresearchdonesincethepast30yrsyoucannotcreateaproductoralanguagewhicheveryonewillfallinlovewithTherearealwayssomeortheotherusecasesorconstraintswhichthecreatorsshouldconsiderConsideringalltheadvantagesatleastforwebdevelopmentIdonotthinkanylanguagegetsclosetotheadvantageswhichgohasevenifyouignoreallthatIsaidaboveGoisacompiledlanguagewhichmeansinproductionyouwonthavetosetupaJVMoravirtualenvandwillinsteadhaveasinglestaticbinaryLikeanicingonacakeallthemodernlibrariesareinthestandardlibrarysuchasthehttpliballowingyoutocreatewebappsingolangwithoutusingathirdpartywebframework
21HelloGoBeforewestartbuildinganapplicationinGoweneedtolearnhowtowriteasimpleprogramYoucantexpecttobuildabuildingwithoutfirstknowinghowtobuilditsfoundationThereforewearegoingtolearnthebasicsyntaxtorunsomesimpleprogramsinthissection
ProgramAccordingtointernationalpracticebeforeyoulearnhowtoprograminsomelanguagesyouwillwanttoknowhowtowriteaprogramtoprintHelloworld
AreyoureadyLetsGo
packagemain
importfmt
funcmain()
fmtPrintf(Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界n)
Itprintsfollowinginformation
Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界
ExplanationOnethingthatyoushouldknowinthefirstisthatGoprogramsarecomposedbypackage
packageltpkgNamegt(Inthiscaseispackagemain)tellsusthissourcefilebelongstomainpackageandthekeywordmaintellsusthispackagewillbecompiledtoaprograminsteadofpackagefileswhoseextensionsarea
Everyexecutableprogramhasoneandonlyonemainpackageandyouneedanentryfunctioncalledmainwithoutanyargumentsorreturnvaluesinthemainpackage
InordertoprintHelloworldhellipwecalledafunctioncalledPrintfThisfunctioniscomingfromfmtpackagesoweimportthispackageinthethirdlineofsourcecodewhichisimportfmt
ThewaytothinkaboutpackagesinGoissimilartoPythonandtherearesomeadvantagesModularity(breakupyourprogramintomanymodules)andreusability(everymodulecanbereusedinmanyprograms)Wejusttalkedaboutconceptsregardingpackagesandwewillmakeourownpackageslater
HelloGo
31
OnthefifthlineweusethekeywordfunctodefinethemainfunctionThebodyofthefunctionisinsideofjustlikeCC++andJava
AsyoucanseetherearenoargumentsWewilllearnhowtowritefunctionswithargumentsinjustasecondandyoucanalsohavefunctionsthathavenoreturnvalueorhaveseveralreturnvalues
OnthesixthlinewecalledthefunctionPrintfwhichisfromthepackagefmtThiswascalledbythesyntaxltpkgNamegtltfuncNamegtwhichisverylikePython-style
Aswementionedinchapter1thepackagesnameandthenameofthefolderthatcontainsthatpackagecanbedifferentHeretheltpkgNamegtcomesfromthenameinpackageltpkgNamegtnotthefoldersname
Youmaynoticethattheexampleabovecontainsmanynon-ASCIIcharactersThepurposeofshowingthisistotellyouthatGosupportsUTF-8bydefaultYoucanuseanyUTF-8characterinyourprograms
EachgofileisinsomepackageandthatpackageshouldbeadistinctfolderintheGOPATHbutmainisaspecialpackagewhichdoesntrequireamainfolderThisisoneaspectwhichtheyleftoutforstandardizationButshouldyouchoosetomakeamainfolderthenyouhavetoensurethatyourunthebinaryproperlyAlsoonegocodecanthavemorethanonemaingofile
~gosrcgithubcomthewhitetulipTasksmain$gobuild~gosrcgithubcomthewhitetulipTasks$mainmain
thethinghereisthatwhenyourcodeisusingsomestaticfilesorsomethingelsethenyououghttorunthebinaryfromtherootoftheapplicationasweseeinthesecondlineaboveIamrunningthemainbinaryoutsidethemainpackagesometimesyoumightwonderwhyyourapplicationisntworkingthenthismightbeoneofthepossibleproblemspleasekeepthisinmind
Onethingyouwillnoticehereisthatgodoesntseetousesemicolonstoendastatementwellitdoesjustthereisaminorcatchtheprogrammerisntexpectedtoputsemicolonsthecompileraddssemicolonstothegocodewhenitcompileswhichisthereasonthatthis(thankfully)isasyntaxerror
funcmain()
becausethecompileraddsasemicolonattheendofmain()whichisasyntaxerrorandasstatedaboveithelpsavoidreligiouswarsiwishtheycombinevimandemacsandcreateauniversaleditorwhichllhelpsavesomemorewarsButfornowwelllearnGo
ConclusionGousespackage(likemodulesinPython)toorganizeprogramsThefunctionmainmain()(thisfunctionmustbeinthemainpackage)istheentrypointofanyprogramGostandardizeslanguageandmostoftheprogrammingmethodologysavingtimeofdeveloperswhichtheydhavewastedinreligiouswarsTherecanbeonlyonemainpackageandonlyonemainfunctioninsideagomainpackageGosupportsUTF-8charactersbecauseoneofthecreatorsofGoisacreatorofUTF-8soGohassupportedmultiplelanguagesfromthetimeitwasborn
LinksDirectoryPrevioussectionGobasicknowledgeNextsectionGofoundation
HelloGo
32
HelloGo
33
22GofoundationInthissectionwearegoingtoteachyouhowtodefineconstantsvariableswithelementarytypesandsomeskillsinGoprogramming
DefinevariablesTherearemanyformsofsyntaxthatcanbeusedtodefinevariablesinGo
ThekeywordvaristhebasicformtodefinevariablesnoticethatGoputsthevariabletypeafterthevariablename
defineavariablewithnameldquovariableNamerdquoandtypetype
varvariableNametype
Definemultiplevariables
definethreevariableswhichtypesaretype
varvname1vname2vname3type
Defineavariablewithinitialvalue
defineavariablewithnameldquovariableNamerdquotypetypeandvaluevalue
varvariableNametype=value
Definemultiplevariableswithinitialvalues
Definethreevariableswithtypetypeandinitializetheirvalues
vname1isv1vname2isv2vname3isv3
varvname1vname2vname3type=v1v2v3
DoyouthinkthatitstootedioustodefinevariablesusethewayaboveDontworrybecausetheGoteamhasalsofoundthistobeaproblemThereforeifyouwanttodefinevariableswithinitialvalueswecanjustomitthevariabletypesothecodewilllooklikethisinstead
Definethreevariableswithouttypetypeandinitializetheirvalues
vname1isv1vname2isv2vname3isv3
varvname1vname2vname3=v1v2v3
WellIknowthisisstillnotsimpleenoughforyouLetsseehowwefixit
Definethreevariableswithouttypetypeandwithoutkeywordvarandinitializetheirvalues
vname1isv1vname2isv2vname3isv3
vname1vname2vname3=v1v2v3
NowitlooksmuchbetterUse=toreplacevarandtypethisiscalledashortassignmentIthasonelimitationthisformcanonlybeusedinsideofafunctionsYouwillgetcompileerrorsifyoutrytouseitoutsideoffunctionbodiesThereforeweusuallyusevartodefineglobalvariables
Gofoundation
34
_(blank)isaspecialvariablenameAnyvaluethatisgiventoitwillbeignoredForexamplewegive35tobanddiscard34(ThisexamplejustshowyouhowitworksItlooksuselessherebecauseweoftenusethissymbolwhenwegetfunctionreturnvalues)
_b=3435
IfyoudontusevariablesthatyouvedefinedinyourprogramthecompilerwillgiveyoucompilationerrorsTrytocompilethefollowingcodeandseewhathappens
packagemain
funcmain()
variint
ConstantsSo-calledconstantsarethevaluesthataredeterminedduringcompiletimeandyoucannotchangethemduringruntimeInGoyoucanusenumberbooleanorstringastypesofconstants
Defineconstantsasfollows
constconstantName=value
youcanassigntypeofconstantsifitsnecessary
constPifloat32=31415926
Moreexamples
constPi=31415926
consti=10000
constMaxThread=10
constprefix=astaxie_
Elementarytypes
Boolean
InGoweusebooltodefineavariableasbooleantypethevaluecanonlybetrueorfalseandfalsewillbethedefaultvalue(Youcannotconvertvariablestypebetweennumberandboolean)
samplecode
varisActiveboolglobalvariable
varenableddisabled=truefalseomittypeofvariables
functest()
varavailableboollocalvariable
valid=falsebriefstatementofvariable
available=trueassignvaluetovariable
Numericaltypes
IntegertypesincludebothsignedandunsignedintegertypesGohasintanduintatthesametimetheyhavesamelengthbutspecificlengthdependsonyouroperatingsystemTheyuse32-bitin32-bitoperatingsystemsand64-bitin64-bitoperatingsystemsGoalsohastypesthathavespecificlengthincludingruneint8int16int32int64byteuint8uint16uint32uint64Notethatruneisaliasofint32andbyteisaliasofuint8
Gofoundation
35
Oneimportantthingyoushouldknowthatyoucannotassignvaluesbetweenthesetypesthisoperationwillcausecompileerrors
varaint8
varbint32
c=a+b
Althoughint32hasalongerlengththanint8andhasthesametypeasintyoucannotassignvaluesbetweenthem(cwillbeassertedastypeinthere)
Floattypeshavethefloat32andfloat64typesandnotypecalledfloatThelatteroneisthedefaulttypeifusingbriefstatement
ThatsallNoGosupportscomplexnumbersaswellcomplex128(witha64-bitrealand64-bitimaginarypart)isthedefaulttypeifyouneedasmallertypethereisonecalledcomplex64(witha32-bitrealand32-bitimaginarypart)ItsformisRE+IMiwhereREisrealpartandIMisimaginarypartthelastiistheimaginarynumberThereisaexampleofcomplexnumber
varccomplex64=5+5i
output(5+5i)
fmtPrintf(Valueisvc)
String
WejusttalkedabouthowGousestheUTF-8charactersetStringsarerepresentedbydoublequotesorbackticks `
samplecode
varfrenchHellostringbasicformtodefinestring
varemptyStringstring=defineastringwithemptystring
functest()
noyesmaybe=noyesmaybebriefstatement
japaneseHello=Ohaiou
frenchHello=Bonjourbasicformofassignvalues
ItsimpossibletochangestringvaluesbyindexYouwillgeterrorswhenyoucompilethefollowingcode
varsstring=hello
s[0]=c
WhatifIreallywanttochangejustonecharacterinastringTrythefollowingcode
s=hello
c=[]byte(s)convertstringto[]bytetype
c[0]=c
s2=string(c)convertbacktostringtype
fmtPrintf(sns2)
Youusethe+operatortocombinetwostrings
s=hello
m=world
a=s+m
fmtPrintf(sna)
andalso
Gofoundation
36
s=hello
s=c+s[1]youcannotchangestringvaluesbyindexbutyoucangetvaluesinstead
fmtPrintf(sns)
WhatifIwanttohaveamultiple-linestring
m=`hello
world`
willnotescapeanycharactersinastring
ErrortypesGohasoneerrortypeforpurposeofdealingwitherrormessagesThereisalsoapackagecallederrorstohandleerrors
err=errorsNew(emitmachodwarfelfheadercorrupted)
iferr=nil
fmtPrint(err)
Underlyingdatastructure
ThefollowingpicturecomesfromanarticleaboutGodatastructureinRussCoxsBlogAsyoucanseeGoutilizesblocksofmemorytostoredata
Figure21Gounderlyingdatastructure
Someskills
Definebygroup
Ifyouwanttodefinemultipleconstantsvariablesorimportpackagesyoucanusethegroupform
Basicform
importfmt
importos
consti=100
constpi=31415
constprefix=Go_
variint
varpifloat32
varprefixstring
Groupform
Gofoundation
37
import(
fmt
os
)
const(
i=100
pi=31415
prefix=Go_
)
var(
iint
pifloat32
prefixstring
)
Unlessyouassignthevalueofconstantisiotathefirstvalueofconstantinthegroupconst()willbe0IffollowingconstantsdontassignvaluesexplicitlytheirvalueswillbethesameasthelastoneIfthevalueoflastconstantisiotathevaluesoffollowingconstantswhicharenotassignedareiotaalso
iotaenumerate
Gohasonekeywordcallediotathiskeywordistomakeenumitbeginswith0increasedby1
const(
x=iotax==0
y=iotay==1
z=iotaz==2
wIfthereisnoexpressionaftertheconstantsnameitusesthelastexpression
soitssayingw=iotaimplicitlyThereforew==3andyandzbothcanomit=iotaaswell
)
constv=iotaonceiotameetskeyword`const`itresetsto`0`sov=0
const(
efg=iotaiotaiotae=0f=0g=0valuesofiotaaresameinoneline
)
Somerules
ThereasonthatGoisconcisebecauseithassomedefaultbehaviors
AnyvariablethatbeginswithacapitallettermeansitwillbeexportedprivateotherwiseThesameruleappliesforfunctionsandconstantsnopublicorprivatekeywordexistsinGo
arrayslicemap
array
arrayisanarrayobviouslywedefineoneasfollows
vararr[n]type
in[n]typenisthelengthofthearraytypeisthetypeofitselementsLikeotherlanguagesweuse[]togetorsetelementvalueswithinarrays
Gofoundation
38
vararr[10]intanarrayoftype[10]int
arr[0]=42arrayis0-based
arr[1]=13assignvaluetoelement
fmtPrintf(Thefirstelementisdnarr[0])
getelementvalueitreturns42
fmtPrintf(Thelastelementisdnarr[9])
itreturnsdefaultvalueof10thelementinthisarraywhichis0inthiscase
Becauselengthisapartofthearraytype[3]intand[4]intaredifferenttypessowecannotchangethelengthofarraysWhenyouusearraysasargumentsfunctionsgettheircopiesinsteadofreferencesIfyouwanttousereferencesyoumaywanttousesliceWelltalkaboutlater
Itspossibletouse=whenyoudefinearrays
a=[3]int123defineanintarraywith3elements
b=[10]int123
defineaintarraywith10elementsofwhichthefirstthreeareassigned
Therestofthemusethedefaultvalue0
c=[]int456use`hellip`toreplacethelengthparameterandGowillcalculateitforyou
YoumaywanttousearraysasarrayselementsLetsseehowtodothis
defineatwo-dimensionalarraywith2elementsandeachelementhas4elements
doubleArray=[2][4]int[4]int1234[4]int5678
Thedeclarationcanbewrittenmoreconciselyasfollows
easyArray=[2][4]int12345678
Arrayunderlyingdatastructure
Figure22Multidimensionalarraymappingrelationship
sliceInmanysituationsthearraytypeisnotagoodchoice-forinstancewhenwedontknowhowlongthearraywillbewhenwedefineitThusweneedadynamicarrayThisiscalledsliceinGo
sliceisnotreallyadynamicarrayItsareferencetypeslicepointstoanunderlyingarraywhosedeclarationissimilartoarraybutdoesntneedlength
justlikedefininganarraybutthistimeweexcludethelength
varfslice[]int
Thenwedefineasliceandinitializeitsdata
slice=[]byteabcd
slicecanredefineexistingslicesorarrayssliceusesarray[ij]toslicewhereiisthestartindexandjisendindexbutnoticethatarray[j]willnotbeslicedsincethelengthofthesliceisj-i
Gofoundation
39
defineanarraywith10elementswhosetypesarebytes
varar=[10]byteabcdefghij
definetwosliceswithtype[]byte
varab[]byte
apointstoelementsfrom3rdto5thinarrayar
a=ar[25]
nowahaselementsar[2]ar[3]andar[4]
bisanothersliceofarrayar
b=ar[35]
nowbhaselementsar[3]andar[4]
NoticethedifferencesbetweensliceandarraywhenyoudefinethemWeuse[hellip]toletGocalculatelengthbutuse[]todefinesliceonly
Theirunderlyingdatastructure
Figure23Correspondencebetweensliceandarray
slicehassomeconvenientoperations
sliceis0-basedar[n]equalstoar[0n]Thesecondindexwillbethelengthofsliceifomittedar[n]equalstoar[nlen(ar)]Youcanusear[]toslicewholearrayreasonsareexplainedinfirsttwostatements
Moreexamplespertainingtoslice
defineanarray
vararray=[10]byteabcdefghij
definetwoslices
varaSlicebSlice[]byte
someconvenientoperations
aSlice=array[3]equalstoaSlice=array[03]aSlicehaselementsabc
aSlice=array[5]equalstoaSlice=array[510]aSlicehaselementsfghij
aSlice=array[]equalstoaSlice=array[010]aSlicehasallelements
slicefromslice
aSlice=array[37]aSlicehaselementsdefglen=4cap=7
bSlice=aSlice[13]bSlicecontainsaSlice[1]aSlice[2]soithaselementsef
bSlice=aSlice[3]bSlicecontainsaSlice[0]aSlice[1]aSlice[2]soithasdef
bSlice=aSlice[05]slicecouldbeexpandedinrangeofcapnowbSlicecontainsdefgh
bSlice=aSlice[]bSlicehassameelementsasaSlicedoeswhicharedefg
sliceisareferencetypesoanychangeswillaffectothervariablespointingtothesamesliceorarrayForinstanceinthecaseofaSliceandbSliceaboveifyouchangethevalueofanelementinaSlicebSlicewillbechangedaswell
sliceislikeastructbydefinitionanditcontains3parts
ApointerthatpointstowhereslicestartsThelengthofsliceCapacitythelengthfromstartindextoendindexofslice
Array_a=[10]byteabcdefghij
Slice_a=Array_a[25]
Theunderlyingdatastructureofthecodeaboveasfollows
Gofoundation
40
Figure24Arrayinformationofslice
Therearesomebuilt-infunctionsforslice
lengetsthelengthofslicecapgetsthemaximumlengthofsliceappendappendsoneormoreelementstosliceandreturnsslicecopycopieselementsfromoneslicetotheotherandreturnsthenumberofelementsthatwerecopied
AttentionappendwillchangethearraythatslicepointstoandaffectotherslicesthatpointtothesamearrayAlsoifthereisnotenoughlengthfortheslice((cap-len)==0)appendreturnsanewarrayforthissliceWhenthishappensotherslicespointingtotheoldarraywillnotbeaffected
map
mapbehaveslikeadictionaryinPythonUsetheformmap[keyType]valueTypetodefineit
LetsseesomecodeThesetandgetvaluesinmaparesimilartoslicehowevertheindexinslicecanonlybeoftypeintwhilemapcanusemuchmorethanthatforexampleintstringorwhateveryouwantAlsotheyareallabletouse==and=tocomparevalues
usestringasthekeytypeintasthevaluetypeand`make`initializeit
varnumbersmap[string]int
anotherwaytodefinemap
numbers=make(map[string]int)
numbers[one]=1assignvaluebykey
numbers[ten]=10
numbers[three]=3
fmtPrintln(Thethirdnumberisnumbers[three])getvalues
ItprintsThethirdnumberis3
Somenoteswhenyouusemap
mapisdisorderlyEverytimeyouprintmapyouwillgetdifferentresultsItsimpossibletogetvaluesbyindex-youhavetousekeymapdoesnthaveafixedlengthItsareferencetypejustlikeslicelenworksformapalsoItreturnshowmanykeysthatmaphasItsquiteeasytochangethevaluethroughmapSimplyusenumbers[one]=11tochangethevalueofkeyoneto11
Youcanuseformkeyvaltoinitializemapsvaluesandmaphasbuilt-inmethodstocheckifthekeyexists
Usedeletetodeleteanelementinmap
Initializeamap
rating=map[string]float32C5Go45Python45C++2
maphastworeturnvaluesForthesecondreturnvalueifthekeydoesnt
existokreturnsfalseItreturnstrueotherwise
csharpRatingok=rating[C]
ifok
fmtPrintln(CisinthemapanditsratingiscsharpRating)
else
fmtPrintln(WehavenoratingassociatedwithCinthemap)
delete(ratingC)deleteelementwithkeyc
AsIsaidabovemapisareferencetypeIftwomapspointtosameunderlyingdataanychangewillaffectbothofthem
Gofoundation
41
m=make(map[string]string)
m[Hello]=Bonjour
m1=m
m1[Hello]=Salutnowthevalueofm[hello]isSalut
makenewmakedoesmemoryallocationforbuilt-inmodelssuchasmapsliceandchannelwhilenewisfortypesmemoryallocation
new(T)allocateszero-valuetotypeTsmemoryreturnsitsmemoryaddresswhichisthevalueoftypeTByGosdefinitionitreturnsapointerwhichpointstotypeTszero-value
newreturnspointers
Thebuilt-infunctionmake(Targs)hasdifferentpurposesthannew(T)makecanbeusedforslicemapandchannelandreturnsatypeTwithaninitialvalueThereasonfordoingthisisbecausetheunderlyingdataofthesethreetypesmustbeinitializedbeforetheypointtothemForexampleaslicecontainsapointerthatpointstotheunderlyingarraylengthandcapacityBeforethesedataareinitializedsliceisnilsoforslicemapandchannelmakeinitializestheirunderlyingdataandassignssomesuitablevalues
makereturnsnon-zerovalues
Thefollowingpictureshowshownewandmakearedifferent
Figure25Underlyingmemoryallocationofmakeandnew
Zero-valuedoesnotmeanemptyvalueItsthevaluethatvariablesdefaulttoinmostcasesHereisalistofsomezero-values
int0
int80
int320
int640
uint0x0
rune0theactualtypeofruneisint32
byte0x0theactualtypeofbyteisuint8
float320lengthis4byte
float640lengthis8byte
boolfalse
string
LinksDirectoryPrevioussectionHelloGoNextsectionControlstatementsandfunctions
Gofoundation
42
23ControlstatementsandfunctionsInthissectionwearegoingtotalkaboutcontrolstatementsandfunctionoperationsinGo
ControlstatementThegreatestinventioninprogrammingisflowcontrolBecauseofthemyouareabletousesimplecontrolstatementsthatcanbeusedtorepresentcomplexlogicTherearethreecategoriesofflowcontrolconditionalcyclecontrolandunconditionaljump
if
ifwillmostlikelybethemostcommonkeywordinyourprogramsIfitmeetstheconditionsthenitdoessomethinganditdoessomethingelseifnot
ifdoesntneedparenthesesinGo
ifxgt10
fmtPrintln(xisgreaterthan10)
else
fmtPrintln(xislessthanorequalto10)
ThemostusefulthingconcerningifinGoisthatitcanhaveoneinitializationstatementbeforetheconditionalstatementThescopeofthevariablesdefinedinthisinitializationstatementareonlyavailableinsidetheblockofthedefiningif
initializexthencheckifxgreaterthan
ifx=computedValue()xgt10
fmtPrintln(xisgreaterthan10)
else
fmtPrintln(xislessthan10)
thefollowingcodewillnotcompile
fmtPrintln(x)
Useif-elseformultipleconditions
ifinteger==3
fmtPrintln(Theintegerisequalto3)
elseifintegerlt3
fmtPrintln(Theintegerislessthan3)
else
fmtPrintln(Theintegerisgreaterthan3)
gotoGohasagotokeywordbutbecarefulwhenyouuseitgotoreroutesthecontrolflowtoapreviouslydefinedlabelwithinthebodyofsamecodeblock
Controlstatementsandfunctions
43
funcmyFunc()
i=0
Herelabelendswith
fmtPrintln(i)
i++
gotoHerejumptolabelHere
Thelabelnameiscasesensitive
for
foristhemostpowerfulcontrollogicinGoItcanreaddatainloopsanditerativeoperationsjustlikewhile
forexpression1expression2expression3
expression1expression2andexpression3areallexpressionswhereexpression1andexpression3arevariabledefinitionsorreturnvaluesfromfunctionsandexpression2isaconditionalstatementexpression1willbeexecutedoncebeforeloopingandexpression3willbeexecutedaftereachloop
Examplesaremoreusefulthanwords
packagemain
importfmt
funcmain()
sum=0
forindex=0indexlt10index++
sum+=index
fmtPrintln(sumisequaltosum)
Printsumisequalto45
SometimesweneedmultipleassignmentsbutGodoesnthavetheoperatorsoweuseparallelassignmentlikeij=i+1j-1
Wecanomitexpression1andexpression3iftheyarenotnecessary
sum=1
forsumlt1000
sum+=sum
OmitaswellFeelfamiliarYesitsidenticaltowhile
sum=1
forsumlt1000
sum+=sum
TherearetwoimportantoperationsinloopswhicharebreakandcontinuebreakjumpsoutoftheloopandcontinueskipsthecurrentloopandstartsthenextoneIfyouhavenestedloopsusebreakalongwithlabels
Controlstatementsandfunctions
44
forindex=10indexgt0index--
ifindex==5
breakorcontinue
fmtPrintln(index)
breakprints109876
continueprints1098764321
forcanreaddatafromarrayslicemapandstringwhenitisusedtogetherwithrange
forkv=rangemap
fmtPrintln(mapskeyk)
fmtPrintln(mapsvalv)
BecauseGosupportsmulti-valuereturnsandgivescompileerrorswhenyoudontusevaluesthatweredefinedyoumaywanttouse_todiscardcertainreturnvalues
for_v=rangemap
fmtPrintln(mapsvalv)
Withgoyoucanaswellcreateaninfiniteloopwhichisequivalenttowhiletrueinotherlanguges
for
yourlogic
switchSometimesyoumayfindthatyouareusingtoomanyif-elsestatementstoimplementsomelogicwhichmaymakeitdifficulttoreadandmaintaininthefutureThisistheperfecttimetousetheswitchstatementtosolvethisproblem
switchsExpr
caseexpr1
someinstructions
caseexpr2
someotherinstructions
caseexpr3
someotherinstructions
default
othercode
ThetypeofsExprexpr1expr2andexpr3mustbethesameswitchisveryflexibleConditionsdonthavetobeconstantsanditexecutesfromtoptobottomuntilitmatchesconditionsIfthereisnostatementafterthekeywordswitchthenitmatchestrue
i=10
switchi
case1
fmtPrintln(iisequalto1)
case234
fmtPrintln(iisequalto23or4)
case10
fmtPrintln(iisequalto10)
default
fmtPrintln(AllIknowisthatiisaninteger)
Controlstatementsandfunctions
45
InthefifthlineweputmanyvaluesinonecaseandwedontneedtoaddthebreakkeywordattheendofcasesbodyItwilljumpoutoftheswitchbodyonceitmatchedanycaseIfyouwanttocontinuetomatchingmorecasesyouneedtousethefallthroughstatement
integer=6
switchinteger
case4
fmtPrintln(integerlt=4)
fallthrough
case5
fmtPrintln(integerlt=5)
fallthrough
case6
fmtPrintln(integerlt=6)
fallthrough
case7
fmtPrintln(integerlt=7)
fallthrough
case8
fmtPrintln(integerlt=8)
fallthrough
default
fmtPrintln(defaultcase)
Thisprogramprintsthefollowinginformation
integerlt=6
integerlt=7
integerlt=8
defaultcase
FunctionsUsethefunckeywordtodefineafunction
funcfuncName(input1type1input2type2)(output1type1output2type2)
functionbody
multi-valuereturn
returnvalue1value2
Wecanextrapolatethefollowinginformationfromtheexampleabove
UsekeywordfunctodefineafunctionfuncNameFunctionshavezerooneormorethanoneargumentsTheargumenttypecomesaftertheargumentnameandargumentsareseparatedbyFunctionscanreturnmultiplevaluesTherearetworeturnvaluesnamedoutput1andoutput2youcanomittheirnamesandusetheirtypeonlyIfthereisonlyonereturnvalueandyouomittedthenameyoudontneedbracketsforthereturnvaluesIfthefunctiondoesnthavereturnvaluesyoucanomitthereturnparametersaltogetherIfthefunctionhasreturnvaluesyouhavetousethereturnstatementsomewhereinthebodyofthefunction
Letsseeonepracticalexample(calculatemaximumvalue)
Controlstatementsandfunctions
46
packagemain
importfmt
returngreatervaluebetweenaandb
funcmax(abint)int
ifagtb
returna
returnb
funcmain()
x=3
y=4
z=5
max_xy=max(xy)callfunctionmax(xy)
max_xz=max(xz)callfunctionmax(xz)
fmtPrintf(max(dd)=dnxymax_xy)
fmtPrintf(max(dd)=dnxzmax_xz)
fmtPrintf(max(dd)=dnyzmax(yz))callfunctionhere
IntheaboveexampletherearetwoargumentsinthefunctionmaxtheirtypesarebothintsothefirsttypecanbeomittedForinstanceabintinsteadofaintbintThesamerulesapplyforadditionalargumentsNoticeherethatmaxonlyhasonereturnvaluesoweonlyneedtowritethetypeofitsreturnvalue-thisistheshortformofwritingit
Multi-valuereturn
OnethingthatGoisbetteratthanCisthatitsupportsmulti-valuereturns
Wellusethefollowingexamplehere
packagemain
importfmt
returnresultsofA+BandAB
funcSumAndProduct(ABint)(intint)
returnA+BAB
funcmain()
x=3
y=4
xPLUSyxTIMESy=SumAndProduct(xy)
fmtPrintf(d+d=dnxyxPLUSy)
fmtPrintf(dd=dnxyxTIMESy)
Theaboveexamplereturnstwovalueswithoutnames-youhavetheoptionofnamingthemalsoIfwenamedthereturnvalueswewouldjustneedtousereturntoreturnthevaluessincetheyareinitializedinthefunctionautomaticallyNoticethatifyourfunctionsaregoingtobeusedoutsideofthepackagewhichmeansyourfunctionnamesstartwithacapitalletteryoudbetterwritecompletestatementsforreturnitmakesyourcodemorereadable
funcSumAndProduct(ABint)(addintmultipliedint)
add=A+B
multiplied=AB
return
Controlstatementsandfunctions
47
Variadicfunctions
GosupportsfunctionswithavariablenumberofargumentsThesefunctionsarecalledvariadicwhichmeansthefunctionallowsanuncertainnumbersofarguments
funcmyfunc(argint)
arghellipinttellsGothatthisisafunctionthathasvariableargumentsNoticethattheseargumentsaretypeintInthebodyoffunctiontheargbecomesasliceofint
for_n=rangearg
fmtPrintf(Andthenumberisdnn)
Passbyvalueandpointers
Whenwepassanargumenttothefunctionthatwascalledthatfunctionactuallygetsthecopyofourvariablessoanychangewillnotaffecttotheoriginalvariable
Letsseeoneexampleinordertoprovewhatimsaying
packagemain
importfmt
simplefunctiontoadd1toa
funcadd1(aint)int
a=a+1wechangevalueofa
returnareturnnewvalueofa
funcmain()
x=3
fmtPrintln(x=x)shouldprintx=3
x1=add1(x)calladd1(x)
fmtPrintln(x+1=x1)shouldprintx+1=4
fmtPrintln(x=x)shouldprintx=3
CanyouseethatEventhoughwecalledadd1withxtheoriginvalueofxdoesntchange
Thereasonisverysimplewhenwecalledadd1wegaveacopyofxtoitnotthexitself
NowyoumayaskhowIcanpasstherealxtothefunction
WeneedusepointershereWeknowvariablesarestoredinmemoryandtheyhavesomememoryaddressesSoifwewanttochangethevalueofavariablewemustchangeitsmemoryaddressThereforethefunctionadd1hastoknowthememoryaddressofxinordertochangeitsvalueHerewepassampxtothefunctionandchangetheargumentstypetothepointertypeintBeawarethatwepassacopyofthepointernotcopyofvalue
Controlstatementsandfunctions
48
packagemain
importfmt
simplefunctiontoadd1toa
funcadd1(aint)int
a=a+1wechangedvalueofa
returnareturnnewvalueofa
funcmain()
x=3
fmtPrintln(x=x)shouldprintx=3
x1=add1(ampx)calladd1(ampx)passmemoryaddressofx
fmtPrintln(x+1=x1)shouldprintx+1=4
fmtPrintln(x=x)shouldprintx=4
NowwecanchangethevalueofxinthefunctionsWhydoweusepointersWhataretheadvantages
AllowsustousemorefunctionstooperateononevariableLowcostbypassingmemoryaddresses(8bytes)copyisnotanefficientwaybothintermsoftimeandspacetopassvariableschannelsliceandmaparereferencetypessotheyusepointerswhenpassingtofunctionsbydefault(AttentionIfyouneedtochangethelengthofsliceyouhavetopasspointersexplicitly)
deferGohasawelldesignedkeywordcalleddeferYoucanhavemanydeferstatementsinonefunctiontheywillexecuteinreverseorderwhentheprogramexecutestotheendoffunctionsInthecasewheretheprogramopenssomeresourcefilesthesefileswouldhavetobeclosedbeforethefunctioncanreturnwitherrorsLetsseesomeexamples
funcReadWrite()bool
fileOpen(file)
Dosomework
iffailureX
fileClose()
returnfalse
iffailureY
fileClose()
returnfalse
fileClose()
returntrue
WesawsomecodebeingrepeatedseveraltimesdefersolvesthisproblemverywellItdoesntonlyhelpyoutowritecleancodebutalsomakesyourcodemorereadable
Controlstatementsandfunctions
49
funcReadWrite()bool
fileOpen(file)
deferfileClose()
iffailureX
returnfalse
iffailureY
returnfalse
returntrue
IftherearemorethanonedeferstheywillexecutebyreverseorderThefollowingexamplewillprint43210
fori=0ilt5i++
deferfmtPrintf(di)
Functionsasvaluesandtypes
FunctionsarealsovariablesinGowecanusetypetodefinethemFunctionsthathavethesamesignaturecanbeseenasthesametype
typetypeNamefunc(input1inputType1input2inputType2[])(result1resultType1[])
WhatstheadvantageofthisfeatureTheansweristhatitallowsustopassfunctionsasvalues
packagemain
importfmt
typetestIntfunc(int)booldefineafunctiontypeofvariable
funcisOdd(integerint)bool
returninteger2=0
funcisEven(integerint)bool
returninteger2==0
passthefunction`f`asanargumenttoanotherfunction
funcfilter(slice[]intftestInt)[]int
varresult[]int
for_value=rangeslice
iff(value)
result=append(resultvalue)
returnresult
varslice=[]int123457
funcmain()
odd=filter(sliceisOdd)
even=filter(sliceisEven)
fmtPrintln(slice=slice)
fmtPrintln(Oddelementsofsliceareodd)
fmtPrintln(Evenelementsofsliceareeven)
Controlstatementsandfunctions
50
ItsveryusefulwhenweuseinterfacesAsyoucanseetestIntisavariablethathasafunctionastypeandthereturnedvaluesandargumentsoffilterarethesameasthoseoftestIntThereforewecanhavecomplexlogicinourprogramswhilemaintainingflexibilityinourcode
PanicandRecover
Godoesnthavetry-catchstructurelikeJavadoesInsteadofthrowingexceptionsGousespanicandrecovertodealwitherrorsHoweveryoushouldntusepanicverymuchalthoughitspowerful
Panicisabuilt-infunctiontobreakthenormalflowofprogramsandgetintopanicstatusWhenafunctionFcallspanicFwillnotcontinueexecutingbutitsdeferfunctionswillcontinuetoexecuteThenFgoesbacktothebreakpointwhichcausedthepanicstatusTheprogramwillnotterminateuntilallofthesefunctionsreturnwithpanictothefirstlevelofthatgoroutinepaniccanbeproducedbycallingpanicintheprogramandsomeerrorsalsocausepaniclikearrayaccessoutofboundserrors
Recoverisabuilt-infunctiontorecovergoroutinesfrompanicstatusCallingrecoverindeferfunctionsisusefulbecausenormalfunctionswillnotbeexecutedwhentheprogramisinthepanicstatusItcatchespanicvaluesiftheprogramisinthepanicstatusanditgetsniliftheprogramisnotinpanicstatus
Thefollowingexampleshowshowtousepanic
varuser=osGetenv(USER)
funcinit()
ifuser==
panic(novaluefor$USER)
Thefollowingexampleshowshowtocheckpanic
functhrowsPanic(ffunc())(bbool)
deferfunc()
ifx=recover()x=nil
b=true
()
f()iffcausespanicitwillrecover
return
mainfunctionandinitfunction
GohastworetentionswhicharecalledmainandinitwhereinitcanbeusedinallpackagesandmaincanonlybeusedinthemainpackageThesetwofunctionsarenotabletohaveargumentsorreturnvaluesEventhoughwecanwritemanyinitfunctionsinonepackageIstronglyrecommendwritingonlyoneinitfunctionforeachpackage
Goprogramswillcallinit()andmain()automaticallysoyoudontneedtocallthembyyourselfForeverypackagetheinitfunctionisoptionalbutpackagemainhasoneandonlyonemainfunction
ProgramsinitializeandbeginexecutionfromthemainpackageIfthemainpackageimportsotherpackagestheywillbeimportedinthecompiletimeIfonepackageisimportedmanytimesitwillbeonlycompiledonceAfterimportingpackagesprogramswillinitializetheconstantsandvariableswithintheimportedpackagesthenexecutetheinitfunctionifitexistsandsoonAfteralltheotherpackagesareinitializedprogramswillinitializeconstantsandvariablesinthemainpackagethenexecutetheinitfunctioninsidethepackageifitexistsThefollowingfigureshowstheprocess
Figure26FlowofprogramsinitializationinGo
Controlstatementsandfunctions
51
import
WeuseimportveryofteninGoprogramsasfollows
import(
fmt
)
Thenweusefunctionsinthatpackageasfollows
fmtPrintln(helloworld)
fmtisfromGostandardlibraryitislocatedwithin$GOROOTpkgGosupportsthird-partypackagesintwoways
1 RelativepathimportmodelloadpackageinthesamedirectoryIdontrecommendthisway2 Absolutepathimportshorturlmodelloadpackageinpath$GOPATHpkgshorturlmodel
Therearesomespecialoperatorswhenweimportpackagesandbeginnersarealwaysconfusedbytheseoperators
1 DotoperatorSometimeweseepeopleusefollowingwaytoimportpackages
import(
fmt
)
ThedotoperatormeansyoucanomitthepackagenamewhenyoucallfunctionsinsideofthatpackageNowfmtPrintf(Helloworld)becomestoPrintf(Helloworld)
2 AliasoperationItchangesthenameofthepackagethatweimportedwhenwecallfunctionsthatbelongtothatpackage
import(
ffmt
)
NowfmtPrintf(Helloworld)becomestofPrintf(Helloworld)3 _operatorThisistheoperatorthatisdifficulttounderstandwithoutsomeoneexplainingittoyou
import(
databasesql
_githubcomziutekmymysqlgodrv
)
The_operatoractuallymeanswejustwanttoimportthatpackageandexecuteitsinitfunctionandwearenotsureifwewanttousethefunctionsbelongingtothatpackage
LinksDirectoryPrevioussectionGofoundationNextsectionstruct
Controlstatementsandfunctions
52
24struct
structWecandefinenewtypesofcontainersofotherpropertiesorfieldsinGojustlikeinotherprogramminglanguagesForexamplewecancreateatypecalledpersontorepresentapersonwithfieldsnameandageWecallthiskindoftypeastruct
typepersonstruct
namestring
ageint
Lookhoweasyitistodefineastruct
Therearetwofields
nameisastringusedtostoreapersonsnameageisaintusedtostoreapersonsage
Letsseehowtouseit
typepersonstruct
namestring
ageint
varPpersonpispersontype
Pname=AstaxieassignAstaxietothefieldnameofp
Page=25assign25tofieldageofp
fmtPrintf(ThepersonsnameissnPname)accessfieldnameofp
Therearethreemorewaystoinitializeastruct
Assigninitialvaluesbyorder
P=personTom25
Usetheformatfieldvaluetoinitializethestructwithoutorder
P=personage24nameBob
Defineananonymousstructtheninitializeit
P=structnamestringageintAmy18
Letsseeacompleteexample
struct
53
packagemain
importfmt
defineanewtype
typepersonstruct
namestring
ageint
structispassedbyvalue
comparetheageoftwopeoplethenreturntheolderpersonanddifferencesofage
funcOlder(p1p2person)(personint)
ifp1agegtp2age
returnp1p1age-p2age
returnp2p2age-p1age
funcmain()
vartomperson
tomnametomage=Tom18
bob=personage25nameBob
paul=personPaul43
tb_Oldertb_diff=Older(tombob)
tp_Oldertp_diff=Older(tompaul)
bp_Olderbp_diff=Older(bobpaul)
fmtPrintf(Ofsandssisolderbydyearsntomnamebobnametb_Oldernametb_diff)
fmtPrintf(Ofsandssisolderbydyearsntomnamepaulnametp_Oldernametp_diff)
fmtPrintf(Ofsandssisolderbydyearsnbobnamepaulnamebp_Oldernamebp_diff)
embeddedfieldsinstructIvejustintroducedtoyouhowtodefineastructwithfieldnamesandtypeInfactGosupportsfieldswithoutnamesbutwithtypesWecalltheseembeddedfields
Whentheembeddedfieldisastructallthefieldsinthatstructwillimplicitlybethefieldsinthestructinwhichithasbeenembedded
Letsseeoneexample
struct
54
packagemain
importfmt
typeHumanstruct
namestring
ageint
weightint
typeStudentstruct
HumanembeddedfielditmeansStudentstructincludesallfieldsthatHumanhas
specialtystring
funcmain()
instantiateandinitializeastudent
mark=StudentHumanMark25120ComputerScience
accessfields
fmtPrintln(Hisnameismarkname)
fmtPrintln(Hisageismarkage)
fmtPrintln(Hisweightismarkweight)
fmtPrintln(Hisspecialtyismarkspecialty)
modifymarksspecialty
markspecialty=AI
fmtPrintln(Markchangedhisspecialty)
fmtPrintln(Hisspecialtyismarkspecialty)
fmtPrintln(MarkbecomeoldHeisnotanathleteanymore)
markage=46
markweight+=60
fmtPrintln(Hisageismarkage)
fmtPrintln(Hisweightismarkweight)
Figure27EmbeddinginStudentandHuman
WeseethatwecanaccesstheageandnamefieldsinStudentjustlikewecaninHumanThisishowembeddedfieldsworkItsverycoolisntitHoldontheressomethingcoolerYoucanevenuseStudenttoaccessHumaninthisembeddedfield
markHuman=HumanMarcus55220
markHumanage-=1
AllthetypesinGocanbeusedasembeddedfields
struct
55
packagemain
importfmt
typeSkills[]string
typeHumanstruct
namestring
ageint
weightint
typeStudentstruct
Humanstructasembeddedfield
Skillsstringsliceasembeddedfield
intbuilt-intypeasembeddedfield
specialtystring
funcmain()
initializeStudentJane
jane=StudentHumanHumanJane35100specialtyBiology
accessfields
fmtPrintln(Hernameisjanename)
fmtPrintln(Herageisjaneage)
fmtPrintln(Herweightisjaneweight)
fmtPrintln(Herspecialtyisjanespecialty)
modifyvalueofskillfield
janeSkills=[]stringanatomy
fmtPrintln(HerskillsarejaneSkills)
fmtPrintln(Sheacquiredtwonewones)
janeSkills=append(janeSkillsphysicsgolang)
fmtPrintln(HerskillsnowarejaneSkills)
modifyembeddedfield
janeint=3
fmtPrintln(Herpreferrednumberisjaneint)
Intheaboveexamplewecanseethatalltypescanbeembeddedfieldsandwecanusefunctionstooperateonthem
ThereisonemoreproblemhoweverIfHumanhasafieldcalledphoneandStudenthasafieldwithsamenamewhatshouldwedo
GouseaverysimplewaytosolveitTheouterfieldsgetupperaccesslevelswhichmeanswhenyouaccessstudentphonewewillgetthefieldcalledphoneinstudentnottheoneintheHumanstructThisfeaturecanbesimplyseenasfieldoverloading
struct
56
packagemain
importfmt
typeHumanstruct
namestring
ageint
phonestringHumanhasphonefield
typeEmployeestruct
Human
specialtystring
phonestringphoneinemployee
funcmain()
Bob=EmployeeHumanBob34777-444-XXXXDesigner333-222
fmtPrintln(BobsworkphoneisBobphone)
fmtPrintln(BobspersonalphoneisBobHumanphone)
LinksDirectoryPrevioussectionControlstatementsandfunctionsNextsectionObject-oriented
struct
57
Object-orientedWetalkedaboutfunctionsandstructsinthelasttwosectionsbutdidyoueverconsiderusingfunctionsasfieldsofastructInthissectionIwillintroduceyoutoanotherformoffunctionthathasareceiverwhichiscalledamethod
methodSupposeyoudefinearectanglestructandyouwanttocalculateitsareaWedtypicallyusethefollowingcodetoachievethisgoal
packagemain
importfmt
typeRectanglestruct
widthheightfloat64
funcarea(rRectangle)float64
returnrwidthrheight
funcmain()
r1=Rectangle122
r2=Rectangle94
fmtPrintln(Areaofr1isarea(r1))
fmtPrintln(Areaofr2isarea(r2))
TheaboveexamplecancalculatearectanglesareaWeusethefunctioncalledareabutitsnotamethodoftherectanglestruct(likeclassmethodsinclassicobject-orientedlanguages)Thefunctionandstructaretwoindependentthingsasyoumaynotice
ItsnotaproblemsofarHoweverifyoualsohavetocalculatetheareaofacirclesquarepentagonoranyotherkindofshapeyouaregoingtoneedtoaddadditionalfunctionswithverysimilarnames
Figure28Relationshipbetweenfunctionandstruct
ObviouslythatsnotcoolAlsotheareashouldreallybethepropertyofacircleorrectangle
ThisiswhereamethodcomestoplayThemethodisafunctionaffiliatedwithatypeIthassimilarsyntaxasfunctionexceptafterthefunckeywordhasaparametercalledthereceiverwhichisthemainbodyofthatmethod
UsingthesameexampleRectangleArea()belongsdirectlytorectangleinsteadofasaperipheralfunctionMorespecificallylengthwidthandArea()allbelongtorectangle
AsRobPikesaid
Amethodisafunctionwithanimplicitfirstargumentcalledareceiver
Syntaxofmethod
func(rReceiverType)funcName(parameters)(results)
Letschangeourexampleusingmethodinstead
Object-oriented
58
packagemain
import(
fmt
math
)
typeCirclestruct
radiusfloat64
typeRectanglestruct
widthheightfloat64
method
func(cCircle)Area()float64
returncradiuscradiusmathPi
method
func(rRectangle)Area()float64
returnrwidthrheight
funcmain()
c1=Circle10
c2=Circle25
r1=Rectangle94
r2=Rectangle122
fmtPrintln(Areaofc1isc1Area())
fmtPrintln(Areaofc2isc2Area())
fmtPrintln(Areaofr1isr1Area())
fmtPrintln(Areaofr2isr2Area())
Notesforusingmethods
IfthenameofmethodsarethesamebuttheydontsharethesamereceiverstheyarenotthesameMethodsareabletoaccessfieldswithinreceiversUsetocallamethodinthestructthesamewayfieldsarecalled
Figure29Methodsaredifferentindifferentstructs
IntheexampleabovetheArea()methodsbelongtobothRectangleandCirclerespectivelysothereceiversareRectangleandCircle
OnethingthatsworthnotingisthatthemethodwithadottedlinemeansthereceiverispassedbyvaluenotbyreferenceThedifferencebetweenthemisthatamethodcanchangeitsreceiversvalueswhenthereceiverispassedbyreferenceanditgetsacopyofthereceiverwhenthereceiverispassedbyvalue
CanthereceiveronlybeastructOfcoursenotAnytypecanbethereceiverofamethodYoumaybeconfusedaboutcustomizedtypesStructisaspecialkindofcustomizedtype-therearemorecustomizedtypes
Usethefollowingformattodefineacustomizedtype
typetypeNametypeLiteral
Examplesofcustomizedtypes
Object-oriented
59
typeageint
typemoneyfloat32
typemonthsmap[string]int
m=months
January31
February28
December31
IhopethatyouknowhowtousecustomizedtypesnowSimilartotypedefinCweuseagestosubstituteintintheaboveexample
Letsgetbacktotalkingaboutmethod
Youcanuseasmanymethodsincustomtypesasyouwant
packagemain
importfmt
const(
WHITE=iota
BLACK
BLUE
RED
YELLOW
)
typeBoxstruct
widthheightdepthfloat64
colorColor
typeColorbyte
typeBoxList[]Boxasliceofboxes
method
func(bBox)Volume()float64
returnbwidthbheightbdepth
methodwithapointerreceiver
func(bBox)SetColor(cColor)
bcolor=c
method
func(blBoxList)BiggestsColor()Color
v=000
k=Color(WHITE)
for_b=rangebl
ifbVolume()gtv
v=bVolume()
k=bcolor
returnk
method
func(blBoxList)PaintItBlack()
fori_=rangebl
bl[i]SetColor(BLACK)
method
func(cColor)String()string
Object-oriented
60
strings=[]stringWHITEBLACKBLUEREDYELLOW
returnstrings[c]
funcmain()
boxes=BoxList
Box444RED
Box10101YELLOW
Box1120BLACK
Box10101BLUE
Box10301WHITE
Box202020YELLOW
fmtPrintf(Wehavedboxesinoursetnlen(boxes))
fmtPrintln(Thevolumeofthefirstoneisboxes[0]Volume()cmsup3)
fmtPrintln(Thecolorofthelastoneisboxes[len(boxes)-1]colorString())
fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())
Letspaintthemallblack
boxesPaintItBlack()
fmtPrintln(Thecolorofthesecondoneisboxes[1]colorString())
fmtPrintln(ObviouslynowthebiggestoneisboxesBiggestsColor()String())
Wedefinesomeconstantsandcustomizedtypes
UseColorasaliasofbyteDefineastructBoxwhichhasfieldsheightwidthlengthandcolorDefineastructBoxListwhichhasBoxasitsfield
Thenwedefinedsomemethodsforourcustomizedtypes
Volume()usesBoxasitsreceiverandreturnsthevolumeofBoxSetColor(cColor)changesBoxscolorBiggestsColor()returnsthecolorwhichhasthebiggestvolumePaintItBlack()setscolorforallBoxinBoxListtoblackString()useColorasitsreceiverreturnsthestringformatofcolorname
IsitmuchclearerwhenweusewordstodescribeourrequirementsWeoftenwriteourrequirementsbeforewestartcoding
Usepointerasreceiver
LetstakealookatSetColormethodItsreceiverisapointerofBoxYesyoucanuseBoxasareceiverWhydoweuseapointerhereBecausewewanttochangeBoxscolorinthismethodThusifwedontuseapointeritwillonlychangethevalueinsideacopyofBox
Ifweseethatareceiveristhefirstargumentofamethoditsnothardtounderstandhowitworks
Youmightbeaskingwhywearentusing(b)Color=cinsteadofbColor=cintheSetColor()methodEitheroneisOKherebecauseGoknowshowtointerprettheassignmentDoyouthinkGoismorefascinatingnow
Youmayalsobeaskingwhetherweshoulduse(ampbl[i])SetColor(BLACK)inPaintItBlackbecausewepassapointertoSetColorAgaineitheroneisOKbecauseGoknowshowtointerpretit
Inheritanceofmethod
WelearnedaboutinheritanceoffieldsinthelastsectionSimilarlywealsohavemethodinheritanceinGoIfananonymousfieldhasmethodsthenthestructthatcontainsthefieldwillhaveallthemethodsfromitaswell
Object-oriented
61
packagemain
importfmt
typeHumanstruct
namestring
ageint
phonestring
typeStudentstruct
Humananonymousfield
schoolstring
typeEmployeestruct
Human
companystring
defineamethodinHuman
func(hHuman)SayHi()
fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)
funcmain()
sam=EmployeeHumanSam45111-888-XXXXGolangInc
mark=StudentHumanMark25222-222-YYYYMIT
samSayHi()
markSayHi()
MethodOverridingIfwewantEmployeetohaveitsownmethodSayHiwecandefineamethodthathasthesamenameinEmployeeanditwillhideSayHiinHumanwhenwecallit
Object-oriented
62
packagemain
importfmt
typeHumanstruct
namestring
ageint
phonestring
typeStudentstruct
Human
schoolstring
typeEmployeestruct
Human
companystring
func(hHuman)SayHi()
fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)
func(eEmployee)SayHi()
fmtPrintf(HiIamsIworkatsCallmeonsnename
ecompanyephone)Yesyoucansplitinto2lineshere
funcmain()
sam=EmployeeHumanSam45111-888-XXXXGolangInc
mark=StudentHumanMark25222-222-YYYYMIT
samSayHi()
markSayHi()
YouareabletowriteanObject-orientedprogramnowandmethodsuseruleofcapitallettertodecidewhetherpublicorprivateaswell
LinksDirectoryPrevioussectionstructNextsectioninterface
Object-oriented
63
26Interface
InterfaceOneofthesubtlestdesignfeaturesinGoareinterfacesAfterreadingthissectionyouwilllikelybeimpressedbytheirimplementation
Whatisaninterface
Inshortaninterfaceisasetofmethodsthatweusetodefineasetofactions
LiketheexamplesinprevioussectionsbothStudentandEmployeecanSayHi()buttheydontdothesamething
LetsdosomemoreworkWelladdonemoremethodSing()tothemalongwiththeBorrowMoney()methodtoStudentandtheSpendSalary()methodtoEmployee
NowStudenthasthreemethodscalledSayHi()Sing()andBorrowMoney()andEmployeehasSayHi()Sing()andSpendSalary()
ThiscombinationofmethodsiscalledaninterfaceandisimplementedbybothStudentandEmployeeSoStudentandEmployeeimplementtheinterfaceSayHi()andSing()AtthesametimeEmployeedoesntimplementtheinterfaceBorrowMoney()andStudentdoesntimplementtheinterfaceSpendSalary()ThisisbecauseEmployeedoesnthavethemethodBorrowMoney()andStudentdoesnthavethemethodSpendSalary()
TypeofInterfaceAninterfacedefinesasetofmethodssoifatypeimplementsallthemethodswesaythatitimplementstheinterface
interface
64
typeHumanstruct
namestring
ageint
phonestring
typeStudentstruct
Human
schoolstring
loanfloat32
typeEmployeestruct
Human
companystring
moneyfloat32
defineinterfaces
typeMeninterface
SayHi()
Sing(lyricsstring)
Guzzle(beerSteinstring)
typeYoungChapinterface
SayHi()
Sing(songstring)
BorrowMoney(amountfloat32)
typeElderlyGentinterface
SayHi()
Sing(songstring)
SpendSalary(amountfloat32)
func(hHuman)SayHi()
fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)
func(hHuman)Sing(lyricsstring)
fmtPrintln(Lalalalalalalalalalalyrics)
func(hHuman)Guzzle(beerSteinstring)
fmtPrintln(GuzzleGuzzleGuzzlebeerStein)
EmployeeoverloadsSayHi
func(eEmployee)SayHi()
fmtPrintf(HiIamsIworkatsCallmeonsnename
ecompanyephone)Yesyoucansplitinto2lineshere
func(sStudent)BorrowMoney(amountfloat32)
sloan+=amount(againandagainand)
func(eEmployee)SpendSalary(amountfloat32)
emoney-=amountMorevodkapleaseGetmethroughtheday
Weknowthataninterfacecanbeimplementedbyanytypeandonetypecanimplementmanyinterfacessimultaneously
Notethatanytypeimplementstheemptyinterfaceinterfacebecauseitdoesnthaveanymethodsandalltypeshavezeromethodsbydefault
Valueofinterface
interface
65
SowhatkindofvaluescanbeputintheinterfaceIfwedefineavariableasatypeinterfaceanytypethatimplementstheinterfacecanassignedtothisvariable
LiketheaboveexampleifwedefineavariablemasinterfaceMenthenanyoneofStudentHumanorEmployeecanbeassignedtomSowecouldhaveasliceofMenandanytypethatimplementsinterfaceMencanassigntothissliceBeawarehoweverthatthesliceofinterfacedoesnthavethesamebehaviorasasliceofothertypes
packagemain
importfmt
typeHumanstruct
namestring
ageint
phonestring
typeStudentstruct
Human
schoolstring
loanfloat32
typeEmployeestruct
Human
companystring
moneyfloat32
InterfaceMenimplementedbyHumanStudentandEmployee
typeMeninterface
SayHi()
Sing(lyricsstring)
method
func(hHuman)SayHi()
fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)
method
func(hHuman)Sing(lyricsstring)
fmtPrintln(Lalalalalyrics)
method
func(eEmployee)SayHi()
fmtPrintf(HiIamsIworkatsCallmeonsnename
ecompanyephone)Yesyoucansplitinto2lineshere
funcmain()
mike=StudentHumanMike25222-222-XXXMIT000
paul=StudentHumanPaul26111-222-XXXHarvard100
sam=EmployeeHumanSam36444-222-XXXGolangInc1000
tom=EmployeeHumanSam36444-222-XXXThingsLtd5000
defineinterfacei
variMen
icanstoreStudent
i=mike
fmtPrintln(ThisisMikeaStudent)
iSayHi()
iSing(Novemberrain)
icanstoreEmployee
i=tom
fmtPrintln(ThisisTomanEmployee)
iSayHi()
interface
66
iSing(Borntobewild)
sliceofMen
fmtPrintln(LetsuseasliceofMenandseewhathappens)
x=make([]Men3)
thesethreeelementsaredifferenttypesbuttheyallimplementedinterfaceMen
x[0]x[1]x[2]=paulsammike
for_value=rangex
valueSayHi()
Aninterfaceisasetofabstractmethodsandcanbeimplementedbynon-interfacetypesItcannotthereforeimplementitself
Emptyinterface
AnemptyinterfaceisaninterfacethatdoesntcontainanymethodssoalltypesimplementanemptyinterfaceThisfactisveryusefulwhenwewanttostorealltypesatsomepointandissimilartovoidinC
defineaasemptyinterface
varvoidinterface
vars
i=5
s=Helloworld
acanstorevalueofanytype
void=i
void=s
Ifafunctionusesanemptyinterfaceasitsargumenttypeitcanacceptanytypeifafunctionusesemptyinterfaceasitsreturnvaluetypeitcanreturnanytype
Methodargumentsofaninterface
AnyvariablecanbeusedinaninterfaceSohowcanweusethisfeaturetopassanytypeofvariabletoafunction
ForexampleweusefmtPrintlnalotbuthaveyouevernoticedthatitcanacceptanytypeofargumentLookingattheopensourcecodeoffmtweseethefollowingdefinition
typeStringerinterface
String()string
ThismeansanytypethatimplementsinterfaceStringercanbepassedtofmtPrintlnasanargumentLetsproveit
interface
67
packagemain
import(
fmt
strconv
)
typeHumanstruct
namestring
ageint
phonestring
HumanimplementsfmtStringer
func(hHuman)String()string
returnName+hname+Age+strconvItoa(hage)+yearsContact+hphone
funcmain()
Bob=HumanBob39000-7777-XXX
fmtPrintln(ThisHumanisBob)
LookingbacktotheexampleofBoxyouwillfindthatColorimplementsinterfaceStringeraswellsoweareabletocustomizetheprintformatIfwedontimplementthisinterfacefmtPrintlnprintsthetypewithitsdefaultformat
fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())
fmtPrintln(ThebiggestoneisboxesBiggestsColor())
AttentionIfthetypeimplementedtheinterfaceerrorfmtwillcallError()soyoudonthavetoimplementStringeratthispoint
TypeofvariableinaninterfaceIfavariableisthetypethatimplementsaninterfaceweknowthatanyothertypethatimplementsthesameinterfacecanbeassignedtothisvariableThequestionishowcanweknowthespecifictypestoredintheinterfaceTherearetwowayswhichIwillshowyou
AssertionofComma-okpattern
Gohasthesyntaxvalueok=element(T)ThischeckstoseeifthevariableisthetypethatweexpectwherevalueisthevalueofthevariableokisavariableofbooleantypeelementistheinterfacevariableandtheTisthetypeofassertion
Iftheelementisthetypethatweexpectokwillbetruefalseotherwise
Letsuseanexampletoseemoreclearly
interface
68
packagemain
import(
fmt
strconv
)
typeElementinterface
typeList[]Element
typePersonstruct
namestring
ageint
func(pPerson)String()string
return(name+pname+-age+strconvItoa(page)+years)
funcmain()
list=make(List3)
list[0]=1anint
list[1]=Helloastring
list[2]=PersonDennis70
forindexelement=rangelist
ifvalueok=element(int)ok
fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)
elseifvalueok=element(string)ok
fmtPrintf(list[d]isastringanditsvalueissnindexvalue)
elseifvalueok=element(Person)ok
fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)
else
fmtPrintf(list[d]isofadifferenttypenindex)
Itsquiteeasytousethispatternbutifwehavemanytypestotestwedbetteruseswitch
switchtest
Letsuseswitchtorewritetheaboveexample
interface
69
packagemain
import(
fmt
strconv
)
typeElementinterface
typeList[]Element
typePersonstruct
namestring
ageint
func(pPerson)String()string
return(name+pname+-age+strconvItoa(page)+years)
funcmain()
list=make(List3)
list[0]=1anint
list[1]=Helloastring
list[2]=PersonDennis70
forindexelement=rangelist
switchvalue=element(type)
caseint
fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)
casestring
fmtPrintf(list[d]isastringanditsvalueissnindexvalue)
casePerson
fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)
default
fmtPrintln(list[d]isofadifferenttypeindex)
Onethingyoushouldrememberisthatelement(type)cannotbeusedoutsideoftheswitchbodywhichmeansinthatcaseyouhavetousethecomma-okpattern
Embeddedinterfaces
ThemostbeautifulthingisthatGohasalotofbuilt-inlogicsyntaxsuchasanonymousfieldsinstructNotsuprisinglywecanuseinterfacesasanonymousfieldsaswellbutwecallthemEmbeddedinterfacesHerewefollowthesamerulesasanonymousfieldsMorespecificallyifaninterfacehasanotherinterfaceembeddedwithinititwillbehaveasifithasallthemethodsthattheembeddedinterfacehas
Wecanseethatthesourcefileincontainerheaphasthefollowingdefinition
typeInterfaceinterface
sortInterfaceembeddedsortInterface
Push(xinterface)aPushmethodtopushelementsintotheheap
Pop()interfaceaPopmethodthatpopselementsfromtheheap
WeseethatsortInterfaceisanembeddedinterfacesotheaboveInterfacehasthethreemethodscontainedwithinthesortInterfaceimplicitly
interface
70
typeInterfaceinterface
Lenisthenumberofelementsinthecollection
Len()int
Lessreturnswhethertheelementwithindexishouldsort
beforetheelementwithindexj
Less(ijint)bool
Swapswapstheelementswithindexesiandj
Swap(ijint)
AnotherexampleistheioReadWriterinpackageio
ioReadWriter
typeReadWriterinterface
Reader
Writer
Reflection
ReflectioninGoisusedfordetermininginformationatruntimeWeusethereflectpackageandTheLawsofReflectionpostexplainshowreflectworksinGo
TherearethreestepsinvolvedwhenusingreflectFirstweneedtoconvertaninterfacetoreflecttypes(reflectTypeorreflectValuethisdependsonthesituation)
t=reflectTypeOf(i)getmeta-dataintypeiandusettogetallelements
v=reflectValueOf(i)getactualvalueintypeiandusevtochangeitsvalue
Afterthatwecanconvertthereflectedtypestogetthevaluesthatweneed
varxfloat64=34
t=reflectTypeOf(x)
v=reflectValueOf(x)
fmtPrintln(typet)
fmtPrintln(valuev)
fmtPrintln(kindisfloat64vKind()==reflectFloat64)
FinallyifwewanttochangethevaluesofthereflectedtypesweneedtomakeitmodifiableAsdiscussedearlierthereisadifferencebetweenpassbyvalueandpassbyreferenceThefollowingcodewillnotcompile
varxfloat64=34
v=reflectValueOf(x)
vSetFloat(71)
Insteadwemustusethefollowingcodetochangethevaluesfromreflecttypes
varxfloat64=34
p=reflectValueOf(ampx)
v=pElem()
vSetFloat(71)
Wehavejustdiscussedthebasicsofreflectionhoweveryoumustpracticemoreinordertounderstandmore
Links
interface
71
DirectoryPrevioussectionObject-orientedNextsectionConcurrency
interface
72
ConcurrencyItissaidthatGoistheCofthe21stcenturyIthinktherearetworeasonsforitFirstGoisasimplelanguageSecondconcurrencyisahottopicintodaysworldandGosupportsthisfeatureatthelanguagelevel
goroutinegoroutinesandconcurrencyarebuiltintothecoredesignofGoTheyresimilartothreadsbutworkdifferentlyGoalsogivesyoufullsupporttosharingmemoryinyourgoroutinesOnegoroutineusuallyuses4~5KBofstackmemoryThereforeitsnothardtorunthousandsofgoroutinesonasinglecomputerAgoroutineismorelightweightmoreefficientandmoreconvenientthansystemthreads
goroutinesrunonthethreadmanageratruntimeinGoWeusethegokeywordtocreateanewgoroutinewhichisafunctionattheunderlyinglevel(main()isagoroutine)
gohello(abc)
Letsseeanexample
packagemain
import(
fmt
runtime
)
funcsay(sstring)
fori=0ilt5i++
runtimeGosched()
fmtPrintln(s)
funcmain()
gosay(world)createanewgoroutine
say(hello)currentgoroutine
Output
hello
world
hello
world
hello
world
hello
world
hello
WeseethatitsveryeasytouseconcurrencyinGobyusingthekeywordgoIntheaboveexamplethesetwogoroutinessharesomememorybutwewouldbetterofffollowingthedesignrecipeDontuseshareddatatocommunicateusecommunicationtosharedata
runtimeGosched()meanslettheCPUexecuteothergoroutinesandcomebackatsomepoint
InGo15theruntimenowsetsthedefaultnumberofthreadstorunsimultaneouslydefinedbyGOMAXPROCStothenumberofcoresavailableontheCPU
Concurrency
73
BeforeGo15ThescheduleronlyusesonethreadtorunallgoroutineswhichmeansitonlyimplementsconcurrencyIfyouwanttousemoreCPUcoresinordertotakeadvantageofparallelprocessingyouhavetocallruntimeGOMAXPROCS(n)tosetthenumberofcoresyouwanttouseIfnlt1itchangesnothing
channelsgoroutinesruninthesamememoryaddressspacesoyouhavetomaintainsynchronizationwhenyouwanttoaccesssharedmemoryHowdoyoucommunicatebetweendifferentgoroutinesGousesaverygoodcommunicationmechanismcalledchannelAchannelisliketwo-waypipelineinUnixshellsusechanneltosendorreceivedataTheonlydatatypethatcanbeusedinchannelsisthetypechannelandthekeywordchanBeawarethatyouhavetousemaketocreateanewchannel
ci=make(chanint)
cs=make(chanstring)
cf=make(chaninterface)
channelusestheoperatorlt-tosendorreceivedata
chlt-vsendvtochannelch
v=lt-chreceivedatafromchandassigntov
Letsseemoreexamples
packagemain
importfmt
funcsum(a[]intcchanint)
total=0
for_v=rangea
total+=v
clt-totalsendtotaltoc
funcmain()
a=[]int728-940
c=make(chanint)
gosum(a[len(a)2]c)
gosum(a[len(a)2]c)
xy=lt-clt-creceivefromc
fmtPrintln(xyx+y)
SendingandreceivingdatainchannelsblocksbydefaultsoitsmucheasiertousesynchronousgoroutinesWhatImeanbyblockisthatagoroutinewillnotcontinuewhenreceivingdatafromanemptychannelie(value=lt-ch)untilothergoroutinessenddatatothischannelOntheotherhandthegoroutinewillnotcontinueuntilthedataitsendstoachannelie(chlt-5)isreceived
BufferedchannelsIintroducednon-bufferedchannelsaboveGoalsohasbufferedchannelsthatcanstoremorethanasingleelementForexamplech=make(chanbool4)herewecreateachannelthatcanstore4booleanelementsSointhischannelweareabletosend4elementsintoitwithoutblockingbutthegoroutinewillbeblockedwhenyoutrytosendafifthelementandnogoroutinereceivesit
Concurrency
74
ch=make(chantypen)
n==0non-buffer(block)
ngt0buffer(non-blockuntilnelementsinthechannel)
Youcantrythefollowingcodeonyourcomputerandchangesomevalues
packagemain
importfmt
funcmain()
c=make(chanint2)change2to1willhaveruntimeerrorbut3isfine
clt-1
clt-2
fmtPrintln(lt-c)
fmtPrintln(lt-c)
RangeandCloseWecanuserangetooperateonbufferchannelsasinsliceandmap
packagemain
import(
fmt
)
funcfibonacci(nintcchanint)
xy=11
fori=0iltni++
clt-x
xy=yx+y
close(c)
funcmain()
c=make(chanint10)
gofibonacci(cap(c)c)
fori=rangec
fmtPrintln(i)
fori=rangecwillnotstopreadingdatafromchanneluntilthechannelisclosedWeusethekeywordclosetoclosethechannelinaboveexampleItsimpossibletosendorreceivedataonaclosedchannelyoucanusevok=lt-chtotestifachannelisclosedIfokreturnsfalseitmeansthethereisnodatainthatchannelanditwasclosed
Remembertoalwaysclosechannelsinproducersandnotinconsumersoritsveryeasytogetintopanicstatus
AnotherthingyouneedtorememberisthatchannelsarenotlikefilesYoudonthavetoclosethemfrequentlyunlessyouaresurethechanneliscompletelyuselessoryouwanttoexitrangeloops
SelectIntheaboveexamplesweonlyuseonechannelbuthowcanwedealwithmorethanonechannelGohasakeywordcalledselecttolistentomanychannels
Concurrency
75
selectisblockingbydefaultanditcontinuestoexecuteonlywhenoneofchannelshasdatatosendorreceiveIfseveralchannelsarereadytouseatthesametimeselectchooseswhichtoexecuterandomly
packagemain
importfmt
funcfibonacci(cquitchanint)
xy=11
for
select
caseclt-x
xy=yx+y
caselt-quit
fmtPrintln(quit)
return
funcmain()
c=make(chanint)
quit=make(chanint)
gofunc()
fori=0ilt10i++
fmtPrintln(lt-c)
quitlt-0
()
fibonacci(cquit)
selecthasadefaultcaseaswelljustlikeswitchWhenallthechannelsarenotreadyforuseitexecutesthedefaultcase(itdoesntwaitforthechannelanymore)
select
casei=lt-c
usei
default
executesherewhencisblocked
TimeoutSometimesagoroutinebecomesblockedHowcanweavoidthistopreventthewholeprogramfromblockingItssimplewecansetatimeoutintheselect
funcmain()
c=make(chanint)
o=make(chanbool)
gofunc()
for
select
casev=lt-c
println(v)
caselt-timeAfter(5timeSecond)
println(timeout)
olt-true
break
()
lt-o
Concurrency
76
RuntimegoroutineThepackageruntimehassomefunctionsfordealingwithgoroutines
runtimeGoexit()
Exitsthecurrentgoroutinebutdeferedfunctionswillbeexecutedasusual
runtimeGosched()
Letstheschedulerexecuteothergoroutinesandcomesbackatsomepoint
runtimeNumCPU()int
ReturnsthenumberofCPUcores
runtimeNumGoroutine()int
Returnsthenumberofgoroutines
runtimeGOMAXPROCS(nint)int
SetshowmanyCPUcoresyouwanttouse
LinksDirectoryPrevioussectioninterfaceNextsectionSummary
Concurrency
77
28SummaryInthischapterwemainlyintroducedthe25GokeywordsLetsreviewwhattheyareandwhattheydo
breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar
varandconstareusedtodefinevariablesandconstantspackageandimportareforpackageusefuncisusedtodefinefunctionsandmethodsreturnisusedtoreturnvaluesinfunctionsormethodsdeferisusedtodefinedeferfunctionsgoisusedtostartanewgoroutineselectisusedtoswitchovermultiplechannelsforcommunicationinterfaceisusedtodefineinterfacesstructisusedtodefinespecialcustomizedtypesbreakcasecontinueforfallthroughelseifswitchgotoanddefaultwereintroducedinsection23chanisthetypeofchannelforcommunicationamonggoroutinestypeisusedtodefinecustomizedtypesmapisusedtodefinemapwhichissimilartohashtablesinotherlanguagesrangeisusedforreadingdatafromslicemapandchannel
Ifyouunderstandhowtousethese25keywordsyouvelearnedalotofGoalready
LinksDirectoryPrevioussectionConcurrencyNextchapterWebfoundation
Summary
78
3WebfoundationThereasonyouarereadingthisbookisthatyouwanttolearntobuildwebapplicationsinGoAsIvesaidbeforeGoprovidesmanypowerfulpackageslikehttpThesepackagescanhelpyoualotwhentryingtobuildwebapplicationsIllteachyoueverythingyouneedtoknowinthefollowingchaptersandwelltalkaboutsomeconceptsofthewebandhowtorunwebapplicationsinGointhischapter
LinksDirectoryPreviouschapterChapter2SummaryNextsectionWebworkingprinciples
Webfoundation
79
WebworkingprinciplesEverytimeyouopenyourbrowserstypesomeURLsandpressenteryouwillseebeautifulwebpagesappearonyourscreenButdoyouknowwhatishappeningbehindthesesimpleactions
NormallyyourbrowserisaclientAfteryoutypeaURLittakesthehostpartoftheURLandsendsittoaDomainNameServer(DNS)inordertogettheIPaddressofthehostThenitconnectstotheIPaddressandaskstosetupaTCPconnectionThebrowsersendsHTTPrequeststhroughtheconnectionTheserverhandlesthemandreplieswithHTTPresponsescontainingthecontentthatmakeupthewebpageFinallythebrowserrendersthebodyofthewebpageanddisconnectsfromtheserver
Figure31Processesofusersvisitawebsite
AwebserveralsoknownasanHTTPserverusestheHTTPprotocoltocommunicatewithclientsAllwebbrowserscanbeconsideredclients
Wecandividethewebsworkingprinciplesintothefollowingsteps
ClientusesTCPIPprotocoltoconnecttoserverClientsendsHTTPrequestpackagestoserverServerreturnsHTTPresponsepackagestoclientIftherequestedresourcesincludedynamicscriptsservercallsscriptenginefirstClientdisconnectsfromserverstartsrenderingHTML
ThisisasimpleworkflowofHTTPaffairs-noticethattheserverclosesitsconnectionsafteritsendsdatatotheclientsthenwaitsforthenextrequest
URLandDNSresolutionWealwaysuseURLstoaccesswebpagesbutdoyouknowhowURLswork
ThefullnameofaURLisUniformResourceLocatorItsfordescribingresourcesontheinternetanditsbasicformisasfollows
schemehost[port]path[query-string][anchor]
schemeassignunderlyingprotocol(suchasHTTPHTTPSFTP)
hostIPordomainnameofHTTPserver
portdefaultportis80anditcanbeomittedinthiscase
IfyouwanttouseotherportsyoumustspecifywhichportForexample
httpwwwcnblogscom8080
pathresourcespath
query-stringdataaresenttoserver
anchoranchor
DNSisanabbreviationofDomainNameSystemItsthenamingsystemforcomputernetworkservicesanditconvertsdomainnamestoactualIPaddressesjustlikeatranslator
Figure32DNSworkingprinciples
TounderstandmoreaboutitsworkingprincipleletsseethedetailedDNSresolutionprocessasfollows
1 AftertypingthedomainnamewwwqqcominthebrowsertheoperatingsystemwillcheckifthereareanymappingrelationshipsinthehostsfilesforthisdomainnameIfsothenthedomainnameresolutioniscomplete
2 IfnomappingrelationshipsexistinthehostsfilestheoperatingsystemwillcheckifanycacheexistsintheDNSIfso
Webworkingprinciples
80
thenthedomainnameresolutioniscomplete3 IfnomappingrelationshipsexistinboththehostandDNScachetheoperatingsystemfindsthefirstDNSresolution
serverinyourTCPIPsettingswhichislikelyyourlocalDNSserverWhenthelocalDNSserverreceivesthequeryifthedomainnamethatyouwanttoqueryiscontainedwithinthelocalconfigurationofitsregionalresourcesitreturnstheresultstotheclientThisDNSresolutionisauthoritative
4 IfthelocalDNSserverdoesntcontainthedomainnamebutamappingrelationshipexistsinthecachethelocalDNSservergivesbackthisresulttotheclientThisDNSresolutionisnotauthoritative
5 IfthelocalDNSservercannotresolvethisdomainnameeitherbyconfigurationofregionalresourcesorcacheitwillproceedtothenextstepwhichdependsonthelocalDNSserverssettings-IfthelocalDNSserverdoesntenableforwardingitroutestherequesttotherootDNSserverthenreturnstheIPaddressofatoplevelDNSserverwhichmayknowthedomainnamecominthiscaseIfthefirsttoplevelDNSserverdoesntrecognizethedomainnameitagainreroutestherequesttothenexttoplevelDNSserveruntilitreachesonethatrecognizesthedomainnameThenthetoplevelDNSserverasksthisnextlevelDNSserverfortheIPaddresscorrespondingtowwwqqcom-IfthelocalDNSserverhasforwardingenableditsendstherequesttoanupperlevelDNSserverIftheupperlevelDNSserveralsodoesntrecognizethedomainnamethentherequestkeepsgettingreroutedtohigherlevelsuntilitfinallyreachesaDNSserverwhichrecognizesthedomainname
WhetherornotthelocalDNSserverenablesforwardingtheIPaddressofthedomainnamealwaysreturnstothelocalDNSserverandthelocalDNSserversendsitbacktotheclient
Figure33DNSresolutionworkflow
RecursivequeryprocesssimplymeansthattheenquirerschangeintheprocessEnquirersdonotchangeinIterativequeryprocesses
NowweknowclientsgetIPaddressesintheendsothebrowsersarecommunicatingwithserversthroughIPaddresses
HTTPprotocolTheHTTPprotocolisacorepartofwebservicesItsimportanttoknowwhattheHTTPprotocolisbeforeyouunderstandhowthewebworks
HTTPistheprotocolthatisusedtofacilitatecommunicationbetweenbrowserandwebserverItisbasedontheTCPprotocolandusuallyusesport80onthesideofthewebserverItisaprotocolthatutilizestherequest-responsemodel-clientssendrequestsandserversrespondAccordingtotheHTTPprotocolclientsalwayssetupnewconnectionsandsendHTTPrequeststoserversServersarenotabletoconnecttoclientsproactivelyorestablishcallbackconnectionsTheconnectionbetweenaclientandaservercanbeclosedbyeithersideForexampleyoucancancelyourdownloadrequestandHTTPconnectionandyourbrowserwilldisconnectfromtheserverbeforeyoufinishdownloading
TheHTTPprotocolisstatelesswhichmeanstheserverhasnoideaabouttherelationshipbetweenthetwoconnectionseventhoughtheyarebothfromsameclientTosolvethisproblemwebapplicationsusecookiestomaintainthestateofconnections
BecausetheHTTPprotocolisbasedontheTCPprotocolallTCPattackswillaffectHTTPcommunicationsinyourserverExamplesofsuchattacksareSYNfloodingDoSandDDoSattacks
HTTPrequestpackage(browserinformation)
RequestpackagesallhavethreepartsrequestlinerequestheaderandbodyThereisoneblanklinebetweenheaderandbody
Webworkingprinciples
81
GETdomainsexampleHTTP11requestlinerequestmethodURLprotocolanditsversion
Hostwwwianaorgdomainname
User-AgentMozilla50(WindowsNT61)AppleWebKit5374(KHTMLlikeGecko)Chrome220122994Safari5374
browserinformation
Accepttexthtmlapplicationxhtml+xmlapplicationxmlq=09q=08mimethatclientscanaccept
Accept-Encodinggzipdeflatesdchstreamcompression
Accept-CharsetUTF-8q=05charactersetinclientside
blankline
bodyrequestresourcearguments(forexampleargumentsinPOST)
Weusefiddlertogetthefollowingrequestinformation
Figure34InformationofaGETrequestcaughtbyfiddler
Figure35InformationofaPOSTrequestcaughtbyfiddler
WecanseethatGETdoesnothavearequestbodyunlikePOSTwhichdoes
TherearemanymethodsyoucanusetocommunicatewithserversinHTTPGETPOSTPUTandDELETEarethe4basicmethodsthatwetypicallyuseAURLrepresentsaresourceonanetworksothese4methodsdefinethequerychangeaddanddeleteoperationsthatcanactontheseresourcesGETandPOSTareverycommonlyusedinHTTPGETcanappendqueryparameterstotheURLusingtoseparatetheURLandparametersandampbetweentheargumentslikeEditPostsaspxname=test1ampid=123456POSTputsdataintherequestbodybecausetheURLimplementsalengthlimitationviathebrowserThusPOSTcansubmitmuchmoredatathanGETAlsowhenwesubmitusernamesandpasswordswedontwantthiskindofinformationtoappearintheURLsoweusePOSTtokeeptheminvisible
HTTPresponsepackage(serverinformation)Letsseewhatinformationiscontainedintheresponsepackages
HTTP11200OKstatusline
Servernginx108webserversoftwareanditsversionintheservermachine
DateDateTue30Oct2012041425GMTrespondedtime
Content-Typetexthtmlrespondeddatatype
Transfer-Encodingchunkeditmeansdataweresentinfragments
Connectionkeep-alivekeepconnection
Content-Length90lengthofbody
blankline
ltDOCTYPEhtmlPUBLIC-W3CDTDXHTML10TransitionalENmessagebody
ThefirstlineiscalledthestatuslineItsuppliestheHTTPversionstatuscodeandstatusmessage
ThestatuscodeinformstheclientofthestatusoftheHTTPserversresponseInHTTP115kindsofstatuscodesweredefined
-1xxInformational
-2xxSuccess
-3xxRedirection
-4xxClientError
-5xxServerError
Letsseemoreexamplesaboutresponsepackages200meansserverrespondedcorrectly302meansredirection
Figure36Fullinformationforvisitingawebsite
HTTPisstatelessandConnectionkeep-alive
Webworkingprinciples
82
ThetermstatelessdoesntmeanthattheserverhasnoabilitytokeepaconnectionItsimplymeansthattheserverdoesntrecognizeanyrelationshipsbetweenanytworequests
InHTTP11Keep-aliveisusedbydefaultIfclientshaveadditionalrequeststheywillusethesameconnectionforthem
NoticethatKeep-alivecannotmaintainoneconnectionforevertheapplicationrunningintheserverdeterminesthelimitwithwhichtokeeptheconnectionaliveforandinmostcasesyoucanconfigurethislimit
Requestinstance
Figure37Allpackagesforopeningonewebpage
WecanseetheentirecommunicationprocessbetweenclientandserverfromtheabovepictureYoumaynoticethattherearemanyresourcefilesinthelistthesearecalledstaticfilesandGohasspecializedprocessingmethodsforthesefiles
ThisisthemostimportantfunctionofbrowserstorequestforaURLandretrievedatafromwebserversthenrendertheHTMLIfitfindssomefilesintheDOMsuchasCSSorJSfilesbrowserswillrequesttheseresourcesfromtheserveragainuntilalltheresourcesfinishrenderingonyourscreen
ReducingHTTPrequesttimesisonewayofimprovingtheloadingspeedofwebpagesByreducingthenumberofCSSandJSfilesthatneedtobeloadedbothrequestlatenciesandpressureonyourwebserverscanbereducedatthesametime
LinksDirectoryPrevioussectionWebfoundationNextsectionBuildasimplewebserver
Webworkingprinciples
83
32BuildasimplewebserverWevediscussedthatwebapplicationsarebasedontheHTTPprotocolandGoprovidesfullHTTPsupportinthenethttppackageItsveryeasytosetawebserverupusingthispackage
Usehttppackagesetupawebserver
packagemain
import(
fmt
nethttp
strings
log
)
funcsayhelloName(whttpResponseWriterrhttpRequest)
rParseForm()parseargumentsyouhavetocallthisbyyourself
fmtPrintln(rForm)printforminformationinserverside
fmtPrintln(pathrURLPath)
fmtPrintln(schemerURLScheme)
fmtPrintln(rForm[url_long])
forkv=rangerForm
fmtPrintln(keyk)
fmtPrintln(valstringsJoin(v))
fmtFprintf(wHelloastaxie)senddatatoclientside
funcmain()
httpHandleFunc(sayhelloName)setrouter
err=httpListenAndServe(9090nil)setlistenport
iferr=nil
logFatal(ListenAndServeerr)
Afterweexecutetheabovecodetheserverbeginslisteningtoport9090inlocalhost
Openyourbrowserandvisithttplocalhost9090YoucanseethatHelloastaxieisonyourscreen
Letstryanotheraddresswithadditionalargumentshttplocalhost9090url_long=111ampurl_long=222
Nowletsseewhathappensonboththeclientandserversides
Youshouldseethefollowinginformationontheserverside
Figure38Serverprintedinformation
Asyoucanseeweonlyneedtocalltwofunctionsinordertobuildasimplewebserver
IfyouareworkingwithPHPyoureprobablyaskingwhetherornotweneedsomethinglikeNginxorApacheTheansweriswedontsinceGolistenstotheTCPportbyitselfandthefunctionsayhelloNameisthelogicfunctionjustlikeacontrollerinPHP
IfyouareworkingwithPythonyoushouldknowtornadoandtheaboveexampleisverysimilartothat
IfyouareworkingwithRubyyoumaynoticeitislikescriptserverinROR(RubyonRails)
Buildasimplewebserver
84
WeusedtwosimplefunctionstosetupasimplewebserverinthissectionandthissimpleserveralreadyhasthecapacityforhighconcurrencyoperationsWewilltalkabouthowtoutilizethisinthenexttwosections
LinksDirectoryPrevioussectionWebworkingprinciplesNextsectionHowGoworkswithweb
Buildasimplewebserver
85
33HowGoworkswithwebWelearnedtousethenethttppackagetobuildasimplewebserverintheprevioussectionandallthoseworkingprinciplesarethesameasthosewewilltalkaboutinthefirstsectionofthischapter
ConceptsinwebprinciplesRequestrequestdatafromusersincludingPOSTGETCookieandURL
Responseresponsedatafromservertoclients
Connconnectionsbetweenclientsandservers
HandlerRequesthandlinglogicandresponsegeneration
httppackageoperatingmechanismThefollowingpictureshowstheworkflowofaGowebserver
Figure39httpworkflow
1 Createalisteningsocketlistentoaportandwaitforclients2 Acceptrequestsfromclients3 HandlerequestsreadHTTPheaderIftherequestusesPOSTmethodreaddatainthemessagebodyandpassthem
tohandlersFinallysocketreturnsresponsedatatoclients
OnceweknowtheanswerstothethreefollowingquestionsitseasytoknowhowthewebworksinGo
HowdowelistentoaportHowdoweacceptclientrequestsHowdoweallocatehandlers
IntheprevioussectionwesawthatGousesListenAndServetohandlethesestepsinitializeaserverobjectcallnetListen(tcpaddr)tosetupaTCPlistenerandlistentoaspecificaddressandport
Letstakealookatthehttppackagessourcecode
HowGoworkswithweb
86
Buildversiongo112
func(srvServer)Serve(lnetListener)error
deferlClose()
vartempDelaytimeDurationhowlongtosleeponacceptfailure
for
rwe=lAccept()
ife=nil
ifneok=e(netError)okampampneTemporary()
iftempDelay==0
tempDelay=5timeMillisecond
else
tempDelay=2
ifmax=1timeSecondtempDelaygtmax
tempDelay=max
logPrintf(httpAccepterrorvretryinginvetempDelay)
timeSleep(tempDelay)
continue
returne
tempDelay=0
cerr=srvnewConn(rw)
iferr=nil
continue
gocserve()
HowdoweacceptclientrequestsafterwebeginlisteningtoaportInthesourcecodewecanseethatsrvServe(netListener)iscalledtohandleclientrequestsInthebodyofthefunctionthereisaforItacceptsarequestcreatesanewconnectionthenstartsanewgoroutinepassingtherequestdatatothegocserve()goroutineThisishowGosupportshighconcurrencyandeverygoroutineisindependent
HowdoweusespecificfunctionstohandlerequestsconnparsesrequestcReadRequest()atfirstthengetsthecorrespondinghandlerhandler=shsrvHandlerwhichisthesecondargumentwepassedwhenwecalledListenAndServeBecausewepassednilGousesitsdefaulthandlerhandler=DefaultServeMuxSowhatisDefaultServeMuxdoinghereWellitstheroutervariablewhichcancallhandlerfunctionsforspecificURLsDidwesetthisYeswedidWedidthisinthefirstlinewhereweusedhttpHandleFunc(sayhelloName)WereusingthisfunctiontoregistertherouterruleforthepathWhentheURListheroutercallsthefunctionsayhelloNameDefaultServeMuxcallsServerHTTPtogethandlerfunctionsfordifferentpathscallingsayhelloNameinthisspecificcaseFinallytheserverwritesdataandrespondstoclients
Detailedworkflow
Figure310WorkflowofhandlinganHTTPrequest
IthinkyoushouldknowhowGorunswebserversnow
LinksDirectoryPrevioussectionBuildasimplewebserverNextsectionGetintohttppackage
HowGoworkswithweb
87
HowGoworkswithweb
88
34GetintohttppackageInprevioussectionswelearnedabouttheworkflowofthewebandtalkedalittlebitaboutGoshttppackageInthissectionwearegoingtolearnabouttwocorefunctionsinthehttppackageConnandServeMux
goroutineinConnUnlikenormalHTTPserversGousesgoroutinesforeveryjobinitiatedbyConninordertoachievehighconcurrencyandperformancesoeveryjobisindependent
Gousesthefollowingcodetowaitfornewconnectionsfromclients
cerr=srvnewConn(rw)
iferr=nil
continue
gocserve()
Asyoucanseeitcreatesanewgoroutineforeveryconnectionandpassesthehandlerthatisabletoreaddatafromtherequesttothegoroutine
CustomizedServeMuxWeusedGosdefaultrouterinprevioussectionswhendiscussingconnserverwiththerouterpassingrequestdatatoaback-endhandler
Thestructofthedefaultrouter
typeServeMuxstruct
musyncRWMutexbecauseofconcurrencywehavetouseamutexhere
mmap[string]muxEntryrouterruleseverystringmappingtoahandler
ThestructofmuxEntry
typemuxEntrystruct
explicitboolexactmatchornot
hHandler
TheinterfaceofHandler
typeHandlerinterface
ServeHTTP(ResponseWriterRequest)routingimplementer
HandlerisaninterfacebutifthefunctionsayhelloNamedidntimplementthisinterfacethenhowdidweadditashandlerTheanswerliesinanothertypecalledHandlerFuncinthehttppackageWecalledHandlerFunctodefineoursayhelloNamemethodsosayhelloNameimplementedHandleratthesametimeItslikewerecallingHandlerFunc(f)andthefunctionfisforceconvertedtotypeHandlerFunc
Getintohttppackage
89
typeHandlerFuncfunc(ResponseWriterRequest)
ServeHTTPcallsf(wr)
func(fHandlerFunc)ServeHTTP(wResponseWriterrRequest)
f(wr)
Howdoestheroutercallhandlersafterwesettherouterrules
TheroutercallsmuxhandlerServeHTTP(wr)whenitreceivesrequestsInotherwordsitcallstheServeHTTPinterfaceofthehandlerswhichhaveimplementedit
Nowletsseehowmuxhandlerworks
func(muxServeMux)handler(rRequest)Handler
muxmuRLock()
defermuxmuRUnlock()
Host-specificpatterntakesprecedenceovergenericones
h=muxmatch(rHost+rURLPath)
ifh==nil
h=muxmatch(rURLPath)
ifh==nil
h=NotFoundHandler()
returnh
TherouterusestherequestsURLasakeytofindthecorrespondinghandlersavedinthemapthencallshandlerServeHTTPtoexecutefunctionstohandlethedata
YoushouldunderstandthedefaultroutersworkflowbynowandGoactuallysupportscustomizedroutersThesecondargumentofListenAndServeisforconfiguringcustomizedroutersItsaninterfaceofHandlerThereforeanyrouterthatimplementstheHandlerinterfacecanbeused
Thefollowingexampleshowshowtoimplementasimplerouter
packagemain
import(
fmt
nethttp
)
typeMyMuxstruct
func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)
ifrURLPath==
sayhelloName(wr)
return
httpNotFound(wr)
return
funcsayhelloName(whttpResponseWriterrhttpRequest)
fmtFprintf(wHellomyroute)
funcmain()
mux=ampMyMux
httpListenAndServe(9090mux)
Getintohttppackage
90
RoutingIfyoudonotwanttouseaRouteryoucanstillachievewhatwewroteintheabovesectionbyreplacingthesecondargumenttoListenAndServetonilandregisteringtheURLsusingaHandleFuncfunctionwhichgoesthroughalltheregisteredURLstofindthebestmatchsocaremustbetakenabouttheorderoftheregistering
samplecode
httpHandleFunc(viewsShowAllTasksFunc)
httpHandleFunc(completeviewsCompleteTaskFunc)
httpHandleFunc(deleteviewsDeleteTaskFunc)
ShowAllTasksFuncisusedtohandletheURLwhichisthedefaultons
TODOaddhttp404error
funcShowAllTasksFunc(whttpResponseWriterrhttpRequest)
ifrMethod==GET
context=dbGetTasks(pending)truewhenyouwantnondeletedtasks
dbisapackagewhichinteractswiththedatabase
ifmessage=
contextMessage=message
homeTemplateExecute(wcontext)
message=
else
message=Methodnotallowed
httpRedirect(wrhttpStatusFound)
ThisisfineforsimpleapplicationswhichdoesntrequiresparameterizedroutingwhatwhenyouneedthatYoucaneitherusetheexistingtoolkitsorframeworksbutsincethisbookisaboutwritingwebappsingolangwearegoingtoteachhowtohandlethisscenarioaswell
WhenthematchismadeontheHandleFuncfunctiontheURLismatchedsosupposewearewritingatodolistmanagerandwewanttodeleteatasksotheURLwedecideforthatapplicationisdelete1soweregisterthedeleteURLlikethishttpHandleFunc(deleteviewsDeleteTaskFunc)delete1thisURLmatchesclosestwiththedeleteURLthananyotherURLsointherURLpathwegettheentireURLoftherequest
httpHandleFunc(deleteviewsDeleteTaskFunc)
DeleteTaskFuncisusedtodeleteatasktrash=movetorecyclebindelete=permanentdelete
funcDeleteTaskFunc(whttpResponseWriterrhttpRequest)
ifrMethod==DELETE
id=rURLPath[len(delete)]
ifid==all
dbDeleteAll()
httpRedirect(wrhttpStatusFound)
else
iderr=strconvAtoi(id)
iferr=nil
fmtPrintln(err)
else
err=dbDeleteTask(id)
iferr=nil
message=Errordeletingtask
else
message=Taskdeleted
httpRedirect(wrhttpStatusFound)
else
message=Methodnotallowed
httpRedirect(wrhttpStatusFound)
Getintohttppackage
91
linkhttpsgithubcomthewhitetulipTasksblobmasterviewsviewsgoL170-L195
InthisabovemethodwhatwebasicallydoisinthefunctionwhichhandlesthedeleteURLwetakeitscompeleteURLwhichisdelete1thenwetakeasliceofthestringandextracteverythingwhichstartsafterthedeletewordwhichistheactualparameterinthiscaseitis1ThenweusethestrconvpackagetoconvertittoanintegeranddeletethetaskwiththattaskID
InmorecomplexscenariostoowecanusethismethodtheadvantageisthatwedonthavetouseanythirdpartytoolkitbutthenagainthirdpartytoolkitsareusefulintheirownrightyouneedtomakeadecisionwhichmethodyoudpreferNoansweristherightanswer
GocodeexecutionflowLetstakealookatthewholeexecutionflow
CallhttpHandleFunc1 CallHandleFuncofDefaultServeMux2 CallHandleofDefaultServeMux3 Addrouterrulestomap[string]muxEntryofDefaultServeMux
CallhttpListenAndServe(9090nil)1 InstantiateServer2 CallListenAndServemethodofServer3 CallnetListen(tcpaddr)tolistentoport4 Startaloopandacceptrequestsintheloopbody5 InstantiateaConnandstartagoroutineforeveryrequestgocserve()6 Readrequestdatawerr=creadRequest()7 CheckwhetherhandlerisemptyornotifitsemptythenuseDefaultServeMux8 CallServeHTTPofhandler9 ExecutecodeinDefaultServeMuxinthiscase10 ChoosehandlerbyURLandexecutecodeinthathandlerfunctionmuxhandlerServeHTTP(wr)11 HowtochoosehandlerACheckrouterrulesforthisURLBCallServeHTTPinthathandlerifthereisoneCCall
ServeHTTPofNotFoundHandlerotherwise
LinksDirectoryPrevioussectionHowGoworkswithwebNextsectionSummary
Getintohttppackage
92
35SummaryInthischapterweintroducedHTTPDNSresolutionflowandhowtobuildasimplewebserverThenwetalkedabouthowGoimplementswebserversforusbylookingatthesourcecodeofthenethttppackage
IhopethatyounowknowmuchmoreaboutwebdevelopmentandyoushouldseethatitsquiteeasyandflexibletobuildawebapplicationinGo
LinksDirectoryPrevioussectionGetintohttppackageNextchapterUserform
Summary
93
4UserformAuserformissomethingthatisverycommonlyusedwhendevelopingwebapplicationsItprovidestheabilitytocommunicatebetweenclientsandserversYoumustbeveryfamiliarwithformsifyouareawebdeveloperifyouareaCC++programmeryoumaywanttoaskwhatisauserform
AformisanareathatcontainsformelementsUserscaninputinformationintoformelementsliketextboxesdropdownlistsradiobuttonscheckboxesetcWeusetheformtagltformgttodefineforms
ltformgt
inputelements
ltformgt
GoalreadyhasmanyconvenientfunctionstodealwithuserformsYoucaneasilygetformdatainHTTPrequestsandtheyareeasytointegrateintoyourownwebapplicationsInsection41wearegoingtotalkabouthowtohandleformdatainGoAlsosinceyoucannottrustanydatacomingfromtheclientsideyoumustfirstvalidatethedatabeforeusingitWellgothroughsomeexamplesabouthowtovalidateformdatainsection42
WesaythatHTTPisstatelessHowcanweidentifythatcertainformsarefromthesameuserAndhowdowemakesurethatoneformcanonlybesubmittedonceWelllookatsomedetailsconcerningcookies(acookieisinformationthatcanbesavedontheclientsideandaddedtotherequestheaderwhentherequestissenttotheserver)inbothsections43and44
Anothercommonuse-caseforformsisuploadingfilesInsection45youwilllearnhowtodothisaswellascontrollingthefileuploadsizebeforeitbeginsuploadinginGo
LinksDirectoryPreviouschapterChapter3SummaryNextsectionProcessforminputs
HTTPForm
94
41ProcessforminputsBeforewebeginletstakealookatasimpleexampleofatypicaluserformsavedaslogingtplinyourprojectfolder
lthtmlgt
ltheadgt
lttitlegtlttitlegt
ltheadgt
ltbodygt
ltformaction=loginmethod=postgt
Usernameltinputtype=textname=usernamegt
Passwordltinputtype=passwordname=passwordgt
ltinputtype=submitvalue=Logingt
ltformgt
ltbodygt
lthtmlgt
ThisformwillsubmittologinontheserverAftertheuserclickstheloginbuttonthedatawillbesenttotheloginhandlerregisteredbytheserverrouterThenweneedtoknowwhetheritusesthePOSTmethodorGET
ThisiseasytofindoutusingthehttppackageLetsseehowtohandletheformdataontheloginpage
Processforminputs
95
packagemain
import(
fmt
htmltemplate
log
nethttp
strings
)
funcsayhelloName(whttpResponseWriterrhttpRequest)
rParseForm()ParseurlparameterspassedthenparsetheresponsepacketforthePOSTbody(requestbody)
attentionIfyoudonotcallParseFormmethodthefollowingdatacannotbeobtainedform
fmtPrintln(rForm)printinformationonserverside
fmtPrintln(pathrURLPath)
fmtPrintln(schemerURLScheme)
fmtPrintln(rForm[url_long])
forkv=rangerForm
fmtPrintln(keyk)
fmtPrintln(valstringsJoin(v))
fmtFprintf(wHelloastaxie)writedatatoresponse
funclogin(whttpResponseWriterrhttpRequest)
fmtPrintln(methodrMethod)getrequestmethod
ifrMethod==GET
t_=templateParseFiles(logingtpl)
tExecute(wnil)
else
rParseForm()
logicpartoflogin
fmtPrintln(usernamerForm[username])
fmtPrintln(passwordrForm[password])
funcmain()
httpHandleFunc(sayhelloName)settingrouterrule
httpHandleFunc(loginlogin)
err=httpListenAndServe(9090nil)settinglisteningport
iferr=nil
logFatal(ListenAndServeerr)
HereweuserMethodtogettherequestmethodanditreturnsanhttpverb-GETPOSTPUTetc
IntheloginfunctionweuserMethodtocheckwhetheritsaloginpageorloginprocessinglogicInotherwordswechecktoseewhethertheuserissimplyopeningthepageortryingtologinServeshowsthepageonlywhentherequestcomesinviatheGETmethodanditexecutestheloginlogicwhentherequestusesthePOSTmethod
Youshouldseethefollowinginterfaceafteropeninghttp1270019090logininyourbrowser
Figure41Userlogininterface
TheserverwillnotprintanythinguntilafterwetypeinausernameandpasswordbecausethehandlerdoesntparsetheformuntilwecallrParseForm()LetsaddrParseForm()beforefmtPrintln(usernamerForm[username])compileourprogramandtestitagainYouwillfindthattheinformationisprintedontheserversidenow
rFormcontainsalloftherequestargumentsforinstancethequery-stringintheURLandthedatainPOSTandPUTIfthedatahasconflictsforexampleparametersthathavethesamenametheserverwillsavethedataintoaslicewithmultiplevaluesTheGodocumentationstatesthatGowillsavethedatafromGETandPOSTrequestsindifferentplaces
Processforminputs
96
Trychangingthevalueoftheactionintheformhttp1270019090logintohttp1270019090loginusername=astaxieinthelogingtplfiletestitagainandyouwillseethatthesliceisprintedontheserverside
Figure42Serverprintsrequestdata
ThetypeofrequestFormisurlValueItsavesdatawiththeformatkey=value
v=urlValues
vSet(nameAva)
vAdd(friendJess)
vAdd(friendSarah)
vAdd(friendZoe)
vEncode()==name=Avaampfriend=Jessampfriend=Sarahampfriend=Zoe
fmtPrintln(vGet(name))
fmtPrintln(vGet(friend))
fmtPrintln(v[friend])
TipsRequestshavetheabilitytoaccessformdatausingtheFormValue()methodForexampleyoucanchangerForm[username]torFormValue(username)andGocallsrParseFormautomaticallyNoticethatitreturnsthefirstvalueifthereareargumentswiththesamenameanditreturnsanemptystringifthereisnosuchargument
LinksDirectoryPrevioussectionUserformNextsectionVerificationofinputs
Processforminputs
97
42VerificationofinputsOneofthemostimportantprinciplesinwebdevelopmentisthatyoucannottrustanythingfromclientsideuserformsYouhavetovalidateallincomingdatabeforeuseitManywebsitesareaffectedbythisproblemwhichissimpleyetcrucial
TherearetwowaysofverifyingformdatathatareincommonuseThefirstisJavaScriptvalidationonthefront-endandthesecondisservervalidationontheback-endInthissectionwearegoingtotalkaboutserversidevalidationinwebdevelopment
RequiredfieldsSometimeswerequirethatusersinputsomefieldsbuttheyfailtocompletethefieldForexampleintheprevioussectionwhenwerequiredausernameYoucanusethelenfunctiontogetthelengthofafieldinordertoensurethatusershaveenteredsomething
iflen(rForm[username][0])==0
codeforemptyfield
rFormtreatsdifferentformelementtypesdifferentlywhentheyareblankForemptytextboxestextareasandfileuploadsitreturnsanemptystringforradiobuttonsandcheckboxesitdoesntevencreatethecorrespondingitemsInsteadyouwillgeterrorsifyoutrytoaccessitThereforeitssafertouserFormGet()togetfieldvaluessinceitwillalwaysreturnemptyifthevaluedoesnotexistOntheotherhandrFormGet()canonlygetonefieldvalueatatimesoyouneedtouserFormtogetthemapofvalues
NumbersSometimesyourequirenumbersratherthanothertextforthefieldvalueForexampleletssaythatyourequiretheageofauserinintegerformonlyie50or10insteadofoldenoughoryoungmanIfwerequireapositivenumberwecanconvertthevaluetotheinttypefirstthenprocessit
getinterr=strconvAtoi(rFormGet(age))
iferr=nil
erroroccurswhenconverttonumberitmaynotanumber
checkrangeofnumber
ifgetintgt100
toobig
Anotherwaytodothisisbyusingregularexpressions
ifm_=regexpMatchString(^[0-9]+$rFormGet(age))m
returnfalse
ForhighperformancepurposesregularexpressionsarenotefficienthoweversimpleregularexpressionsareusuallyfastenoughIfyouarefamiliarwithregularexpressionsitsaveryconvenientwaytoverifydataNoticethatGousesRE2soallUTF-8charactersaresupported
Chinese
Validationofinputs
98
SometimesweneeduserstoinputtheirChinesenamesandwehavetoverifythattheyalluseChineseratherthanrandomcharactersForChineseverificationregularexpressionsaretheonlyway
ifm_=regexpMatchString(^[x4e00-x9fa5]+$rFormGet(realname))m
returnfalse
EnglishlettersSometimesweneeduserstoinputonlyEnglishlettersForexamplewerequiresomeonesEnglishnamelikeastaxieinsteadofasta谢Wecaneasilyuseregularexpressionstoperformourverification
ifm_=regexpMatchString(^[a-zA-Z]+$rFormGet(engname))m
returnfalse
E-mailaddressIfyouwanttoknowwhetherusershaveenteredvalidE-mailaddressesyoucanusethefollowingregularexpression
ifm_=regexpMatchString(`^([w_]210)(w1)([a-z]24)$`rFormGet(email))m
fmtPrintln(no)
else
fmtPrintln(yes)
DropdownlistLetssaywerequireanitemfromourdropdownlistbutinsteadwegetavaluefabricatedbyhackersHowdowepreventthisfromhappening
Supposewehavethefollowingltselectgt
ltselectname=fruitgt
ltoptionvalue=applegtappleltoptiongt
ltoptionvalue=peargtpearltoptiongt
ltoptionvalue=bananagtbananaltoptiongt
ltselectgt
Wecanusethefollowingstrategytosanitizeourinput
slice=[]stringapplepearbanana
for_v=rangeslice
ifv==rFormGet(fruit)
returntrue
returnfalse
AllthefunctionsIveshownaboveareinmyopensourceprojectforoperatingonslicesandmapshttpsgithubcomastaxiebeeku
Radiobuttons
Validationofinputs
99
Ifwewanttoknowwhethertheuserismaleorfemalewemayusearadiobuttonreturning1formaleand2forfemaleHoweversomelittlekidwhojustreadhisfirstbookonHTTPdecidestosendtoyoua3WillyourprogramthrowanexceptionAsyoucanseeweneedtousethesamemethodaswedidforourdropdownlisttomakesurethatonlyexpectedvaluesarereturnedbyourradiobutton
ltinputtype=radioname=gendervalue=1gtMale
ltinputtype=radioname=gendervalue=2gtFemale
Andweusethefollowingcodetovalidatetheinput
slice=[]int12
for_v=rangeslice
ifv==rFormGet(gender)
returntrue
returnfalse
CheckboxesSupposetherearesomecheckboxesforuserinterestsandthatyoudontwantextraneousvalueshereeitherYoucanvalidatetheseasefollows
ltinputtype=checkboxname=interestvalue=footballgtFootball
ltinputtype=checkboxname=interestvalue=basketballgtBasketball
ltinputtype=checkboxname=interestvalue=tennisgtTennis
Inthiscasethesanitizationisalittlebitdifferenttovalidatingthebuttonandcheckboxinputssinceherewegetaslicefromthecheckboxes
slice=[]stringfootballbasketballtennis
a=Slice_diff(rForm[interest]slice)
ifa==nil
returntrue
returnfalse
DateandtimeSupposeyouwantuserstoinputvaliddatesortimesGohasthetimepackageforconvertingyearmonthanddaytotheircorrespondingtimesAfterthatitseasytocheckit
t=timeDate(2009timeNovember1023000timeUTC)
fmtPrintf(GolaunchedatsntLocal())
Afteryouhavethetimeyoucanusethetimepackageformoreoperationsdependingonyourneeds
InthissectionwevediscussedsomecommonmethodsofvalidatingformdataontheserversideIhopethatyounowunderstandmoreaboutdatavalidationinGoespeciallyhowtouseregularexpressionstoyouradvantage
LinksDirectory
Validationofinputs
100
PrevioussectionProcessforminputsNextsectionCrosssitescripting
Validationofinputs
101
43CrosssitescriptingTodayswebsiteshavemuchmoredynamiccontentinordertoimproveuserexperiencewhichmeansthatwemustprovidedynamicinformationdependingoneveryindividualsbehaviorUnfortunatelydynamicwebsitesaresusceptibletomaliciousattacksknownasCrosssitescripting(knownasXSS)StaticwebsitesarenotsusceptibletoCrosssitescripting
AttackersofteninjectmaliciousscriptslikeJavaScriptVBScriptActiveXorFlashintothosewebsitesthathaveloopholesOncetheyhavesuccessfullyinjectedtheirscriptsuserinformationcanbestolenandyourwebsitecanbefloodedwithspamTheattackerscanalsochangeusersettingstowhatevertheywant
Ifyouwishtopreventthiskindofattackyoushouldcombinethefollowingtwoapproaches
ValidationofalldatafromuserswhichwetalkedaboutintheprevioussectionCarefullyhandledatathatwillbesenttoclientsinordertopreventanyinjectedscriptsfromrunningonbrowsers
SohowcanwedothesetwothingsinGoFortunatelythehtmltemplatepackagehassomeusefulfunctionstoescapedataasfollows
funcHTMLEscape(wioWriterb[]byte)escapesbtowfuncHTMLEscapeString(sstring)stringreturnsastringafterescapingfromsfuncHTMLEscaper(argsinterface)stringreturnsastringafterescapingfrommultiplearguments
Letschangetheexampleinsection41
fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printatserverside
fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))
templateHTMLEscape(w[]byte(rFormGet(username)))respondedtoclients
Ifsomeonetriestoinputtheusernameasltscriptgtalert()ltscriptgtwewillseethefollowingcontentinthebrowser
Figure43JavaScriptafterescaped
FunctionsinthehtmltemplatepackagehelpyoutoescapeallHTMLtagsWhatifyoujustwanttoprintltscriptgtalert()ltscriptgttobrowsersYoushouldusetexttemplateinstead
importtexttemplate
terr=templateNew(foo)Parse(`defineTHelloend`)
err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)
Output
Helloltscriptgtalert(youhavebeenpwned)ltscriptgt
OryoucanusethetemplateHTMLtypeVariablecontentwillnotbeescapedifitstypeistemplateHTML
importhtmltemplate
terr=templateNew(foo)Parse(`defineTHelloend`)
err=tExecuteTemplate(outTtemplateHTML(ltscriptgtalert(youhavebeenpwned)ltscriptgt))
Output
Helloltscriptgtalert(youhavebeenpwned)ltscriptgt
Crosssitescripting
102
Onemoreexampleofescaping
importhtmltemplate
terr=templateNew(foo)Parse(`defineTHelloend`)
err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)
Output
Helloampltscriptampgtalert(amp39youhavebeenpwnedamp39)ampltscriptampgt
LinksDirectoryPrevioussectionVerificationofinputsNextsectionDuplicatesubmissions
Crosssitescripting
103
44DuplicatesubmissionsIdontknowifyouveeverseensomeblogsorBBSthathavemorethanonepostthatareexactlythesamebutIcantellyouthatitsbecauseuserssubmittedduplicatepostformsTherearemanythingsthatcancauseduplicatesubmissionssometimesusersjustdoubleclickthesubmitbuttonortheywanttomodifysomecontentafterpostingandpressthebackbuttonInsomecasesitisbytheintentionalactionsofmalicioususersItseasytoseehowduplicatesubmissionscanleadtomanyproblemsThuswehavetouseeffectivemeanstopreventit
ThesolutionistoaddahiddenfieldwithauniquetokentoyourformandtoalwayscheckthistokenbeforeprocessingtheincomingdataAlsoifyouareusingAjaxtosubmitaformuseJavaScripttodisablethesubmitbuttononcetheformhasbeensubmitted
Letsimprovetheexamplefromsection42
ltinputtype=checkboxname=interestvalue=footballgtFootball
ltinputtype=checkboxname=interestvalue=basketballgtBasketball
ltinputtype=checkboxname=interestvalue=tennisgtTennis
Usernameltinputtype=textname=usernamegt
Passwordltinputtype=passwordname=passwordgt
ltinputtype=hiddenname=tokenvalue=gt
ltinputtype=submitvalue=Logingt
WeuseanMD5hash(timestamp)togeneratethetokenandaddedittobothahiddenfieldontheclientsideformandasessioncookieontheserverside(Chapter6)Wecanthenusethistokentocheckwhetherornotthisformwassubmitted
funclogin(whttpResponseWriterrhttpRequest)
fmtPrintln(methodrMethod)getrequestmethod
ifrMethod==GET
crutime=timeNow()Unix()
h=md5New()
ioWriteString(hstrconvFormatInt(crutime10))
token=fmtSprintf(xhSum(nil))
t_=templateParseFiles(logingtpl)
tExecute(wtoken)
else
loginrequest
rParseForm()
token=rFormGet(token)
iftoken=
checktokenvalidity
else
giveerrorifnotoken
fmtPrintln(usernamelengthlen(rForm[username][0]))
fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printinserverside
fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))
templateHTMLEscape(w[]byte(rFormGet(username)))respondtoclient
Figure44Thecontentinbrowserafteraddingatoken
YoucanrefreshthispageandyouwillseeadifferenttokeneverytimeThisensuresthateveryformisunique
FornowyoucanpreventmanyduplicatesubmissionattacksbyaddingtokenstoyourformsbutitcannotpreventalldeceptiveattacksofthistypeThereismuchmoreworkthatneedstobedone
Duplicatesubmissions
104
LinksDirectoryPrevioussectionCrosssitescriptingNextsectionFileupload
Duplicatesubmissions
105
45FileuploadSupposeyouhaveawebsitelikeInstagramandyouwantuserstouploadtheirbeautifulphotosHowwouldyouimplementthatfunctionality
YouhavetoaddpropertyenctypetotheformthatyouwanttouseforuploadingphotosTherearethreepossiblevaluesforthisproperty
applicationx-www-form-urlencodedTranscodeallcharactersbeforeuploading(default)
multipartform-dataNotranscodingYoumustusethisvaluewhenyourformhasfileuploadcontrols
textplainConvertspacesto+butnotranscodingforspecialcharacters
ThereforetheHTMLcontentofafileuploadformshouldlooklikethis
lthtmlgt
ltheadgt
lttitlegtUploadfilelttitlegt
ltheadgt
ltbodygt
ltformenctype=multipartform-dataaction=http1270019090uploadmethod=postgt
ltinputtype=filename=uploadfilegt
ltinputtype=hiddenname=tokenvalue=gt
ltinputtype=submitvalue=uploadgt
ltformgt
ltbodygt
lthtmlgt
Weneedtoaddafunctionontheserversidetohandlethisform
httpHandleFunc(uploadupload)
uploadlogic
funcupload(whttpResponseWriterrhttpRequest)
fmtPrintln(methodrMethod)
ifrMethod==GET
crutime=timeNow()Unix()
h=md5New()
ioWriteString(hstrconvFormatInt(crutime10))
token=fmtSprintf(xhSum(nil))
t_=templateParseFiles(uploadgtpl)
tExecute(wtoken)
else
rParseMultipartForm(32ltlt20)
filehandlererr=rFormFile(uploadfile)
iferr=nil
fmtPrintln(err)
return
deferfileClose()
fmtFprintf(wvhandlerHeader)
ferr=osOpenFile(test+handlerFilenameosO_WRONLY|osO_CREATE0666)
iferr=nil
fmtPrintln(err)
return
deferfClose()
ioCopy(ffile)
Fileupload
106
AsyoucanseeweneedtocallrParseMultipartFormforuploadingfilesThefunctionParseMultipartFormtakesthemaxMemoryargumentAfteryoucallParseMultipartFormthefilewillbesavedintheservermemorywithmaxMemorysizeIfthefilesizeislargerthanmaxMemorytherestofthedatawillbesavedinasystemtemporaryfileYoucanuserFormFiletogetthefilehandleanduseioCopytosavetoyourfilesystem
YoudontneedtocallrParseFormwhenyouaccessothernon-filefieldsintheformbecauseGowillcallitwhenitsnecessaryAlsocallingParseMultipartFormonceisenough-multiplecallsmakenodifference
Weusethreestepsforuploadingfilesasfollows
1 Addenctype=multipartform-datatoyourform2 CallrParseMultipartFormontheserversidetosavethefileeithertomemoryortoatemporaryfile3 CallrFormFiletogetthefilehandleandsavetothefilesystem
ThefilehandleristhemultipartFileHeaderItusesthefollowingstruct
typeFileHeaderstruct
Filenamestring
HeadertextprotoMIMEHeader
containsfilteredorunexportedfields
Figure45Printinformationonserverafterreceivingfile
ClientsuploadfilesIshowedanexampleofusingaformtoauploadafileWecanimpersonateaclientformtouploadfilesinGoaswell
Fileupload
107
packagemain
import(
bytes
fmt
io
ioioutil
mimemultipart
nethttp
os
)
funcpostFile(filenamestringtargetUrlstring)error
bodyBuf=ampbytesBuffer
bodyWriter=multipartNewWriter(bodyBuf)
thisstepisveryimportant
fileWritererr=bodyWriterCreateFormFile(uploadfilefilename)
iferr=nil
fmtPrintln(errorwritingtobuffer)
returnerr
openfilehandle
fherr=osOpen(filename)
iferr=nil
fmtPrintln(erroropeningfile)
returnerr
deferfhClose()
iocopy
_err=ioCopy(fileWriterfh)
iferr=nil
returnerr
contentType=bodyWriterFormDataContentType()
bodyWriterClose()
resperr=httpPost(targetUrlcontentTypebodyBuf)
iferr=nil
returnerr
deferrespBodyClose()
resp_bodyerr=ioutilReadAll(respBody)
iferr=nil
returnerr
fmtPrintln(respStatus)
fmtPrintln(string(resp_body))
returnnil
sampleusage
funcmain()
target_url=httplocalhost9090upload
filename=astaxiepdf
postFile(filenametarget_url)
TheaboveexampleshowsyouhowtouseaclienttouploadfilesItusesmultipartWritetowritefilesintocacheandsendsthemtotheserverthroughthePOSTmethod
IfyouhaveotherfieldsthatneedtowriteintodatalikeusernamecallmultipartWriteFieldasneeded
Links
Fileupload
108
DirectoryPrevioussectionDuplicatesubmissionsNextsectionSummary
Fileupload
109
46SummaryInthischapterwemainlylearnedhowtoprocessformdatainGothroughseveralexampleslikelogginginusersanduploadingfilesWealsoemphasizedthatvalidatinguserdataisextremelyimportantforwebsitesecurityandweusedonesectiontotalkabouthowtofilterdatawithregularexpressions
Ihopethatyounowknowmoreaboutthecommunicationprocessbetweenclientandserver
LinksDirectoryPrevioussectionFileuploadNextchapterDatabase
Summary
110
5DatabaseForwebdevelopersthedatabaseisatthecoreofwebdevelopmentYoucansavealmostanythingintoadatabaseandqueryorupdatedatainsideitlikeuserinformationproductsornewsarticles
GodoesntprovideanydatabasedriversbutitdoeshaveadriverinterfacedefinedinthedatabasesqlpackagePeoplecandevelopdatabasedriversbasedonthatinterfaceInsection51wearegoingtotalkaboutdatabasedriverinterfacedesigninGoInsections52to54IwillintroducesomeSQLdatabasedriverstoyouInsection55IwillpresenttheORM thatIhavedevelopedwhichisbasedonthedatabasesqlinterfacestandardItiscompatiblewithmostdriversthathaveimplementedthedatabasesqlinterfaceanditmakesiteasytoaccessdatabasesidiomaticallyinGo
NoSQLhasbeenahottopicinrecentyearsMorewebsitesaredecidingtouseNoSQLdatabasesastheirmaindatabaseinsteadofjustforthepurposeofcachingIwillintroduceyoutotwoNoSQLdatabaseswhichareMongoDBandRedisinsection56
LinksDirectoryPreviousChapterChapter4SummaryNextsectiondatabasesqlinterface
Database
111
51databasesqlinterfaceGodoesntprovideanyofficialdatabasedriversunlikeotherlanguageslikePHPwhichdoHoweveritdoeshavesomedatabasedriverinterfacestandardsfordeveloperstodevelopdatabasedriverswithTheadvantageisthatifyourcodeisdevelopedaccordingtotheseinterfacestandardsyouwillnotneedtochangeanycodeifyourdatabasechangesLetsseewhatthesedatabaseinterfacestandardsare
sqlRegisterThisfunctionisinthedatabasesqlpackageforregisteringdatabasedriverswhenyouusethird-partydatabasedriversAlloftheseshouldcalltheRegister(namestringdriverdriverDriver)functionininit()inordertoregisterthemselves
Letstakealookatthecorrespondingmymysqlandsqlite3drivercode
httpsgithubcommattngo-sqlite3driver
funcinit()
sqlRegister(sqlite3ampSQLiteDriver)
httpsgithubcommikespookmymysqldriver
Driverautomaticallyregisteredindatabasesql
vard=Driverprototcpraddr1270013306
funcinit()
Register(SETNAMESutf8)
sqlRegister(mymysqlampd)
Weseethatallthird-partydatabasedriversimplementthisfunctiontoregisterthemselvesandGousesamaptosaveuserdriversinsideofdatabasesql
vardrivers=make(map[string]driverDriver)
drivers[name]=driver
Thereforethisregistrationfunctioncanregisterasmanydriversasyoumayrequireeachwithdifferentnames
Wealwaysseethefollowingcodewhenweusethird-partydrivers
import(
databasesql
_githubcommattngo-sqlite3
)
Heretheunderscore(alsoknownasablank)_canbequiteconfusingformanybeginnersbutthisisagreatfeatureinGoWealreadyknowthatthisunderscoreidentifierisusedfordiscardingvaluesfromfunctionreturnsandalsothatyoumustuseallpackagesthatyouveimportedinyourcodeinGoSowhentheblankisusedwithimportitmeansthatyouneedtoexecutetheinit()functionofthatpackagewithoutdirectlyusingitwhichisaperfectfitfortheuse-caseofregisteringdatabasedrivers
driverDriverDriverisaninterfacecontaininganOpen(namestring)methodthatreturnsaConninterface
databasesqlinterface
112
typeDriverinterface
Open(namestring)(Connerror)
Thisisaone-timeConnwhichmeansitcanonlybeusedoncepergoroutineThefollowingcodewillcauseerrorstooccur
gogoroutineA(Conn)query
gogoroutineB(Conn)insert
BecauseGohasnoideawhichgoroutinedoeswhichoperationthequeryoperationmaygettheresultoftheinsertoperationandvice-versa
Allthird-partydriversshouldhavethisfunctiontoparsethenameofConnandreturnthecorrectresults
driverConnThisisadatabaseconnectioninterfacewithsomemethodsandasivesaidabovethesameConncanonlybeusedoncepergoroutine
typeConninterface
Prepare(querystring)(Stmterror)
Close()error
Begin()(Txerror)
PreparereturnsthepreparestatusofcorrespondingSQLcommandsforqueryinganddeletingetcCloseclosesthecurrentconnectionandcleansresourcesMostthird-partydriversimplementsomekindofconnectionpoolsoyoudontneedtocacheconnectionswhichcancauseunexpectederrorsBeginreturnsaTxthatrepresentsatransactionhandleYoucanuseitforqueryingupdatingrollingbacktransactionsetc
driverStmtThisisareadystatusthatcorrespondswithConnsoitcanonlybeusedoncepergoroutine(asisthecasewithConn)
typeStmtinterface
Close()error
NumInput()int
Exec(args[]Value)(Resulterror)
Query(args[]Value)(Rowserror)
CloseclosesthecurrentconnectionbutstillreturnsrowdataifitisexecutingaqueryoperationNumInputreturnsthenumberofobligateargumentsDatabasedriversshouldchecktheircallersargumentswhentheresultisgreaterthan0anditreturns-1whendatabasedriversdontknowanyobligateargumentExecexecutestheupdateinsertSQLcommandspreparedinPreparereturnsResultQueryexecutestheselectSQLcommandpreparedinPreparereturnsrowdata
driverTx
databasesqlinterface
113
Generallytransactionhandlesonlyhavesubmitorrollbackmethodsanddatabasedriversonlyneedtoimplementthesetwomethods
typeTxinterface
Commit()error
Rollback()error
driverExecerThisisanoptionalinterface
typeExecerinterface
Exec(querystringargs[]Value)(Resulterror)
IfthedriverdoesntimplementthisinterfacewhenyoucallDBExecitwillautomaticallycallPreparethenreturnStmtAfterthatitexecutestheExecmethodofStmtthenclosesStmt
driverResultThisistheinterfaceforresultsofupdateinsertoperations
typeResultinterface
LastInsertId()(int64error)
RowsAffected()(int64error)
LastInsertIdreturnsauto-incrementIdnumberafteradatabaseinsertoperationRowsAffectedreturnsrowsthatwereaffectedbyqueryoperations
driverRowsThisistheinterfacefortheresultofaqueryoperation
typeRowsinterface
Columns()[]string
Close()error
Next(dest[]Value)error
ColumnsreturnsfieldinformationofdatabasetablesTheslicehasaone-to-onecorrespondencewithSQLqueryfieldsonlyanddoesnotreturnallfieldsofthatdatabasetableCloseclosesRowsiteratorNextreturnsnextdataandassignstodestconvertingallstringsintobytearraysandgetsioEOFerrorifnomoredataisavailable
driverRowsAffectedThisisanaliasofint64butitimplementstheResultinterface
databasesqlinterface
114
typeRowsAffectedint64
func(RowsAffected)LastInsertId()(int64error)
func(vRowsAffected)RowsAffected()(int64error)
driverValueThisisanemptyinterfacethatcancontainanykindofdata
typeValueinterface
TheValuemustbesomethingthatdriverscanoperateonornilsoitshouldbeoneofthefollowingtypes
int64
float64
bool
[]byte
string[]ExceptRowsNextwhichcannotreturnstring
timeTime
driverValueConverterThisdefinesaninterfaceforconvertingnormalvaluestodriverValue
typeValueConverterinterface
ConvertValue(vinterface)(Valueerror)
Thisinterfaceiscommonlyusedindatabasedriversandhasmanyusefulfeatures
ConvertsdriverValuetoacorrespondingdatabasefieldtypeforexampleconvertsint64touint16ConvertsdatabasequeryresultstodriverValueConvertsdriverValuetoauserdefinedvalueinthescanfunction
driverValuerThisdefinesaninterfaceforreturningdriverValue
typeValuerinterface
Value()(Valueerror)
ManytypesimplementthisinterfaceforconversionbetweendriverValueanditself
AtthispointyoushouldknowabitaboutdevelopingdatabasedriversinGoOnceyoucanimplementinterfacesforoperationslikeadddeleteupdateetcthereareonlyafewproblemsleftrelatedtocommunicatingwithspecificdatabases
databasesqldatabasesqldefinesevenmorehigh-levelmethodsontopofdatabasesqldriverformoreconvenientdatabaseoperationsanditsuggeststhatyouimplementaconnectionpool
databasesqlinterface
115
typeDBstruct
driverdriverDriver
dsnstring
musyncMutexprotectsfreeConnandclosed
freeConn[]driverConn
closedbool
AsyoucanseetheOpenfunctionreturnsaDBthathasafreeConnandthisisasimpleconnectionpoolItsimplementationisverysimpleanduglyItusesdeferdbputConn(cierr)intheDbpreparefunctiontoputaconnectionintotheconnectionpoolEverytimeyoucalltheConnfunctionitchecksthelengthoffreeConnIfitsgreaterthan0thatmeansthereisareusableconnectionanditdirectlyreturnstoyouOtherwiseitcreatesanewconnectionandreturns
LinksDirectoryPrevioussectionDatabaseNextsectionMySQL
databasesqlinterface
116
52MySQLTheLAMPstackhasbeenverypopularontheinternetinrecentyearsandtheMinLAMPstandforMySQLMySQLisfamousbecauseitsopensourceandeasytouseAssuchithasbecomethede-factodatabaseintheback-endsofmanywebsites
MySQLdriversThereareacoupleofdriversthatsupportMySQLinGoSomeofthemimplementthedatabasesqlinterfaceandothersusetheirowninterfacestandards
httpsgithubcomgo-sql-drivermysqlsupportsdatabasesqlwritteninpureGohttpsgithubcomziutekmymysqlsupportsdatabasesqlanduserdefinedinterfaceswritteninpureGo
Illusethefirstdriverinthefollowingexamples(Iusethisoneinmypersonalprojectstoo)andIalsorecommendthatyouuseitforthefollowingreasons
ItsanewdatabasedriverandsupportsmorefeaturesItfullysupportsdatabasesqlinterfacestandardsSupportskeep-alivelongconnectionswiththread-safety
SamplesInthefollowingsectionsIllusethesamedatabasetablestructurefordifferentdatabasesthencreateSQLasfollows
CREATETABLE`userinfo`(
`uid`INT(10)NOTNULLAUTO_INCREMENT
`username`VARCHAR(64)NULLDEFAULTNULL
`departname`VARCHAR(64)NULLDEFAULTNULL
`created`DATENULLDEFAULTNULL
PRIMARYKEY(`uid`)
)
Thefollowingexampleshowshowtooperateonadatabasebasedonthedatabasesqlinterfacestandards
packagemain
import(
_githubcomgo-sql-drivermysql
databasesql
fmt
)
funcmain()
dberr=sqlOpen(mysqlastaxieastaxietestcharset=utf8)
checkErr(err)
insert
stmterr=dbPrepare(INSERTuserinfoSETusername=departname=created=)
checkErr(err)
reserr=stmtExec(astaxie研发部门2012-12-09)
checkErr(err)
iderr=resLastInsertId()
checkErr(err)
fmtPrintln(id)
update
HowtouseMySQL
117
stmterr=dbPrepare(updateuserinfosetusername=whereuid=)
checkErr(err)
reserr=stmtExec(astaxieupdateid)
checkErr(err)
affecterr=resRowsAffected()
checkErr(err)
fmtPrintln(affect)
query
rowserr=dbQuery(SELECTFROMuserinfo)
checkErr(err)
forrowsNext()
varuidint
varusernamestring
vardepartmentstring
varcreatedstring
err=rowsScan(ampuidampusernameampdepartmentampcreated)
checkErr(err)
fmtPrintln(uid)
fmtPrintln(username)
fmtPrintln(department)
fmtPrintln(created)
delete
stmterr=dbPrepare(deletefromuserinfowhereuid=)
checkErr(err)
reserr=stmtExec(id)
checkErr(err)
affecterr=resRowsAffected()
checkErr(err)
fmtPrintln(affect)
dbClose()
funccheckErr(errerror)
iferr=nil
panic(err)
Letmeexplainafewoftheimportantfunctionshere
sqlOpen()opensaregistereddatabasedriverTheGo-MySQL-DriverregisteredthemysqldriverhereThesecondargumentistheDSN(DataSourceName)thatdefinesinformationpertainingtothedatabaseconnectionItsupportsfollowingformats
userunix(pathtosocket)dbnamecharset=utf8
userpasswordtcp(localhost5555)dbnamecharset=utf8
userpassworddbname
userpasswordtcp([deadbeefcafe]80)dbname
dbPrepare()returnsaSQLoperationthatisgoingtobeexecutedItalsoreturnstheexecutionstatusafterexecutingSQL
dbQuery()executesSQLandreturnsaRowsresultstmtExec()executesSQLthathasbeenpreparedandstoredinStmt
Notethatweusetheformat=topassargumentsThisisnecessaryforpreventingSQLinjectionattacks
HowtouseMySQL
118
LinksDirectoryPrevioussectiondatabasesqlinterfaceNextsectionSQLite
HowtouseMySQL
119
53SQLiteSQLiteisanopensourceembeddedrelationaldatabaseIthasaself-containedzero-configurationandtransaction-supporteddatabaseengineItscharacteristicsarehighlyportableeasytousecompactefficientandreliableInmostofcasesyouonlyneedabinaryfileofSQLitetocreateconnectandoperateadatabaseIfyouarelookingforanembeddeddatabasesolutionSQLiteisworthconsideringYoucansaySQLiteistheopensourceversionofAccess
SQLitedriversTherearemanydatabasedriversforSQLiteinGobutmanyofthemdonotsupportthedatabasesqlinterfacestandards
httpsgithubcommattngo-sqlite3supportsdatabasesqlbasedoncgohttpsgithubcomfeyeleanorgosqlite3doesntsupportdatabasesqlbasedoncgohttpsgithubcomphfgo-sqlite3doesntsupportdatabasesqlbasedoncgo
ThefirstdriveristheonlyonethatsupportsthedatabasesqlinterfacestandardinitsSQLitedriversoIusethisinmyprojects-itwillmakeiteasytomigratemycodeinthefutureifIneedto
SamplesWecreatethefollowingSQL
CREATETABLE`userinfo`(
`uid`INTEGERPRIMARYKEYAUTOINCREMENT
`username`VARCHAR(64)NULL
`departname`VARCHAR(64)NULL
`created`DATENULL
)
Anexample
packagemain
import(
databasesql
fmt
time
_githubcommattngo-sqlite3
)
funcmain()
dberr=sqlOpen(sqlite3foodb)
checkErr(err)
insert
stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)values())
checkErr(err)
reserr=stmtExec(astaxie研发部门2012-12-09)
checkErr(err)
iderr=resLastInsertId()
checkErr(err)
fmtPrintln(id)
update
stmterr=dbPrepare(updateuserinfosetusername=whereuid=)
checkErr(err)
HowtouseSQLite
120
reserr=stmtExec(astaxieupdateid)
checkErr(err)
affecterr=resRowsAffected()
checkErr(err)
fmtPrintln(affect)
query
rowserr=dbQuery(SELECTFROMuserinfo)
checkErr(err)
varuidint
varusernamestring
vardepartmentstring
varcreatedtimeTime
forrowsNext()
err=rowsScan(ampuidampusernameampdepartmentampcreated)
checkErr(err)
fmtPrintln(uid)
fmtPrintln(username)
fmtPrintln(department)
fmtPrintln(created)
rowsClose()goodhabittoclose
delete
stmterr=dbPrepare(deletefromuserinfowhereuid=)
checkErr(err)
reserr=stmtExec(id)
checkErr(err)
affecterr=resRowsAffected()
checkErr(err)
fmtPrintln(affect)
dbClose()
funccheckErr(errerror)
iferr=nil
panic(err)
YoumayhavenoticedthatthecodeisalmostthesameasintheprevioussectionandthatweonlychangedthenameoftheregistereddriverandcalledsqlOpentoconnecttoSQLiteinadifferentway
Notethatsometimesyoucantusetheforstatementbecauseyoudonthavemorethanonerowthenyoucanusetheifstatement
ifrowsNext()
err=rowsScan(ampuidampusernameampdepartmentampcreated)
checkErr(err)
fmtPrintln(uid)
fmtPrintln(username)
fmtPrintln(department)
fmtPrintln(created)
AlsoyouhavetodoarowsNext()withoutusingthatyoucantfetchdataintheScanfunction
Transactions
HowtouseSQLite
121
TheaboveexampleshowshowyoufetchdatafromthedatabasebutwhenyouwanttowriteawebapplicationthenitwillnotonlybenecessarytofetchdatafromthedbbutitwillalsoberequiredtowritedataintoitForthatpurposeyoushouldusetransactionsbecauseforvariousreasonssuchashavingmultiplegoroutineswhichaccessthedatabasethedatabasemightgetlockedThisisundesirableinyourwebapplicationandtheuseoftransactionsiseffectiveinensuringyourdatabaseactivitieseitherpassorfailcompletelydependingoncircumstancesItisclearthatusingtransactionscanpreventalotofthingsfromgoingwrongwiththewebapp
trashSQLerr=databasePrepare(updatetasksetis_deleted=Ylast_modified_at=datetime()whereid=)
iferr=nil
fmtPrintln(err)
txerr=databaseBegin()
iferr=nil
fmtPrintln(err)
_err=txStmt(trashSQL)Exec(id)
iferr=nil
fmtPrintln(doingrollback)
txRollback()
else
txCommit()
Asitisclearfromtheaboveblockofcodeyoufirstprepareastatementafterwhichyouexecuteitdependingontheoutputofthatexecutionthenyoueitherrollitbackorcommitit
AsafinalnoteonthissectionthereisausefulSQLitemanagementtoolavailablehttpsqlitebrowserorg
LinksDirectoryPrevioussectionMySQLNextsectionPostgreSQL
HowtouseSQLite
122
54PostgreSQLPostgreSQLisanobject-relationaldatabasemanagementsystemavailableformanyplatformsincludingLinuxFreeBSDSolarisMicrosoftWindowsandMacOSXItisreleasedunderanMIT-stylelicenseandisthusfreeandopensourcesoftwareItslargerthanMySQLbecauseitsdesignedforenterpriseusageasanalternativetoOraclePostgresqlisagoodchoiceforenterprisetypeprojects
PostgreSQLdriversTherearemanydatabasedriversavailableforPostgreSQLHerearethreeexamplesofthem
httpsgithubcomlibpqsupportsdatabasesqlwritteninpureGohttpsgithubcomjbarhamgopgsqldriversupportsdatabasesqlwritteninpureGohttpsgithubcomlxngo-pgsqlsupportsdatabasesqlwritteninpureGo
Iwillusethefirstoneintheexamplesthatfollow
SamplesWecreatethefollowingSQL
CREATETABLEuserinfo
(
uidserialNOTNULL
usernamecharactervarying(100)NOTNULL
departnamecharactervarying(500)NOTNULL
Createddate
CONSTRAINTuserinfo_pkeyPRIMARYKEY(uid)
)
WITH(OIDS=FALSE)
Anexample
packagemain
import(
databasesql
fmt
_githubcomlibpq
time
)
const(
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=test
)
funcmain()
dbinfo=fmtSprintf(user=spassword=sdbname=ssslmode=disable
DB_USERDB_PASSWORDDB_NAME)
dberr=sqlOpen(postgresdbinfo)
checkErr(err)
deferdbClose()
fmtPrintln(Insertingvalues)
varlastInsertIdint
err=dbQueryRow(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3)returninguidastax
ie研发部门2012-12-09)Scan(amplastInsertId)
HowtousePostgreSQL
123
checkErr(err)
fmtPrintln(lastinsertedid=lastInsertId)
fmtPrintln(Updating)
stmterr=dbPrepare(updateuserinfosetusername=$1whereuid=$2)
checkErr(err)
reserr=stmtExec(astaxieupdatelastInsertId)
checkErr(err)
affecterr=resRowsAffected()
checkErr(err)
fmtPrintln(affectrowschanged)
fmtPrintln(Querying)
rowserr=dbQuery(SELECTFROMuserinfo)
checkErr(err)
forrowsNext()
varuidint
varusernamestring
vardepartmentstring
varcreatedtimeTime
err=rowsScan(ampuidampusernameampdepartmentampcreated)
checkErr(err)
fmtPrintln(uid|username|department|created)
fmtPrintf(3v|8v|6v|6vnuidusernamedepartmentcreated)
fmtPrintln(Deleting)
stmterr=dbPrepare(deletefromuserinfowhereuid=$1)
checkErr(err)
reserr=stmtExec(lastInsertId)
checkErr(err)
affecterr=resRowsAffected()
checkErr(err)
fmtPrintln(affectrowschanged)
funccheckErr(errerror)
iferr=nil
panic(err)
NotethatPostgreSQLusesthe$1$2formatinsteadofthethatMySQLusesandithasadifferentDSNformatinsqlOpenAnotherthingisthatthePostgreSQLdriverdoesnotsupportsqlResultLastInsertId()Soinsteadofthis
stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3))
reserr=stmtExec(astaxie研发部门2012-12-09)
fmtPrintln(resLastInsertId())
usedbQueryRow()andScan()togetthevalueforthelastinsertedid
err=dbQueryRow(INSERTINTOTABLE_NAMEvalues($1)returninguidVALUE1)Scan(amplastInsertId)
fmtPrintln(lastInsertId)
LinksDirectoryPrevioussectionSQLite
HowtousePostgreSQL
124
NextsectionDevelopORMbasedonbeedb
HowtousePostgreSQL
125
55DevelopORMbasedonbeedb(Projectbeedbisnolongermaintainedbutthecodesstillthere)
beedbisanORM(object-relationalmapper)developedinGobymeItusesidiomaticGotooperateondatabasesimplementingstruct-to-databasemappingandactsasalightweightGoORMframeworkThepurposeofdevelopingthisORMisnotonlytohelppeoplelearnhowtowriteanORMbutalsotofindagoodbalancebetweenfunctionalityandperformancewhenitcomestodatapersistence
beedbisanopensourceprojectthatsupportsbasicORMfunctionalitybutdoesntsupportassociationqueries
BecausebeedbsupportsdatabasesqlinterfacestandardsanydriverthatimplementsthisinterfacecanbeusedwithbeedbIvetestedthefollowingdrivers
Mysqlgithubgo-mysql-drivermysql
PostgreSQLgithubcomlibpq
SQLitegithubcommattngo-sqlite3
Mysqlgithubcomziutekmymysqlgodrv
MSADODBgithubcommattngo-adodb
Oraclegithubcommattngo-oci8
ODBCbitbucketorgmiquellamgodbc
InstallationYoucanusegogettoinstallbeedblocally
gogetgithubcomastaxiebeedb
InitializationFirstyouhavetoimportallthenecessarypackages
import(
databasesql
githubcomastaxiebeedb
_githubcomziutekmymysqlgodrv
)
Thenyouneedtoopenadatabaseconnectionandcreateabeedbobject(MySQLinthisexample)
dberr=sqlOpen(mymysqltestxiemengjun123456)
iferr=nil
panic(err)
orm=beedbNew(db)
beedbNew()actuallyhastwoargumentsThefirstisthedatabaseobjectandthesecondisforindicatingwhichdatabaseengineyoureusingIfyoureusingMySQLSQLiteyoucanjustskipthesecondargument
OtherwisethisargumentmustbesuppliedForinstanceinthecaseofSQLServer
HowtousebeedbORM
126
orm=beedbNew(dbmssql)
PostgreSQL
orm=beedbNew(dbpg)
beedbsupportsdebuggingUsethefollowingcodetoenableit
beedbOnDebug=true
NextwehaveastructfortheUserinfodatabasetablethatweusedinprevioussections
typeUserinfostruct
Uidint`PK`iftheprimarykeyisnotidyouneedtoaddtag`PK`foryourcustomizedprimarykey
Usernamestring
Departnamestring
CreatedtimeTime
Beawarethatbeedbauto-convertscamelcasenamestolowersnakecaseForexampleifwehaveUserInfoasthestructnamebeedbwillconvertittouser_infointhedatabaseThesameruleappliestostructfieldnames
InsertdataThefollowingexampleshowsyouhowtousebeedbtosaveastructinsteadofusingrawSQLcommandsWeusethebeedbSavemethodtoapplythechange
varsaveoneUserinfo
saveoneUsername=TestAddUser
saveoneDepartname=TestAddDepartname
saveoneCreated=timeNow()
ormSave(ampsaveone)
YoucanchecksaveoneUidaftertherecordisinserteditsvalueisaself-incrementedIDwhichtheSavemethodtakescareofforyou
beedbprovidesanotherwayofinsertingdatathisisviaGosmaptype
add=make(map[string]interface)
add[username]=astaxie
add[departname]=clouddevelop
add[created]=2012-12-02
ormSetTable(userinfo)Insert(add)
Insertmultipledata
addslice=make([]map[string]interface10)
add=make(map[string]interface)
add2=make(map[string]interface)
add[username]=astaxie
add[departname]=clouddevelop
add[created]=2012-12-02
add2[username]=astaxie2
add2[departname]=clouddevelop2
add2[created]=2012-12-02
addslice=append(addsliceaddadd2)
ormSetTable(userinfo)InsertBatch(addslice)
HowtousebeedbORM
127
ThemethodshownaboveissimilartoachainedquerywhichyoushouldbefamiliarwithifyouveeverusedjqueryItreturnstheoriginalORMobjectaftercallsthencontinuesdoingotherjobs
ThemethodSetTabletellstheORMwewanttoinsertourdataintotheuserinfotable
UpdatedataLetscontinueworkingwiththeaboveexampletoseehowtoupdatedataNowthatwehavetheprimarykeyofsaveone(Uid)beedbexecutesanupdateoperationinsteadofinsertinganewrecord
saveoneUsername=UpdateUsername
saveoneDepartname=UpdateDepartname
saveoneCreated=timeNow()
ormSave(ampsaveone)update
Likebeforeyoucanalsousemapforupdatingdata
t=make(map[string]interface)
t[username]=astaxie
ormSetTable(userinfo)SetPK(uid)Where(2)Update(t)
Letmeexplainsomeofthemethodsusedabove
SetPK()tellstheORMthatuidistheprimarykeyrecordsintheuserinfotableWhere()setsconditionsandsupportsmultipleargumentsIfthefirstargumentisanintegeritsashortformforWhere(ltprimarykeygt=ltvaluegt)Update()methodacceptsamapandupdatesthedatabase
QuerydataThebeedbqueryinterfaceisveryflexibleLetsseesomeexamples
Example1querybyprimarykey
varuserUserinfo
Whereacceptstwoargumentssupportsintegers
ormWhere(uid=27)Find(ampuser)
Example2
varuser2Userinfo
ormWhere(3)Find(ampuser2)shortformthatomitsprimarykey
Example3otherqueryconditions
varuser3Userinfo
Wheretwoargumentsareacceptedwithsupportforchartype
ormWhere(name=john)Find(ampuser3)
Example4morecomplexconditions
varuser4Userinfo
Wherethreeargumentsareaccepted
ormWhere(name=andageltjohn88)Find(ampuser4)
Examplestogetmultiplerecords
HowtousebeedbORM
128
Example1gets10recordswithidgt3thatstartswithposition20
varallusers[]Userinfo
err=ormWhere(idgt3)Limit(1020)FindAll(ampallusers)
Example2omitsthesecondargumentoflimitsoitstartswith0andgets10records
vartenusers[]Userinfo
err=ormWhere(idgt3)Limit(10)FindAll(amptenusers)
Example3getsallrecords
vareveryone[]Userinfo
err=ormOrderBy(uiddescusernameasc)FindAll(ampeveryone)
AsyoucanseetheLimitmethodisforlimitingthenumberofresults
Limit()supportstwoargumentsthenumberofresultsandthestartingposition0isthedefaultvalueofthestartingpositionOrderBy()isfororderingresultsTheargumentistheordercondition
AlltheexamplesherearesimplymappingrecordstostructsYoucanalsojustputthedataintoamapasfollows
a_=ormSetTable(userinfo)SetPK(uid)Where(2)Select(uidusername)FindMap()
Select()tellsbeedbhowmanyfieldsyouwanttogetfromthedatabasetableIfunspecifiedallfieldsarereturnedbydefaultFindMap()returnsthe[]map[string][]bytetypesoyouneedtoconverttoothertypesyourself
Deletedatabeedbprovidesrichmethodstodeletedata
Example1deleteasinglerecord
saveoneistheoneinaboveexample
ormDelete(ampsaveone)
Example2deletemultiplerecords
alluseristheslicewhichgetsmultiplerecords
ormDeleteAll(ampalluser)
Example3deleterecordsbySQL
ormSetTable(userinfo)Where(uidgt3)DeleteRow()
AssociationqueriesbeedbdoesntsupportjoiningbetweenstructsHoweversincesomeapplicationsneedthisfeaturehereisanimplementation
a_=ormSetTable(userinfo)Join(LEFTuserdetailuserinfouid=userdetailuid)
Where(userinfouid=1)Select(userinfouiduserinfousernameuserdetailprofile)FindMap()
HowtousebeedbORM
129
WeseeanewmethodcalledJoin()thathasthreearguments
ThefirstargumentTypeofJoinINNERLEFTOUTERCROSSetcThesecondargumentthetableyouwanttojoinwithThethirdargumentjoincondition
GroupByandHavingbeedbalsohasanimplementationofgroupbyandhaving
a_=ormSetTable(userinfo)GroupBy(username)Having(username=astaxie)FindMap()
GroupBy()indicatesthefieldthatisforgroupbyHaving()indicatesconditionsofhaving
FutureIhavereceivedalotoffeedbackonbeedbfrommanypeopleallaroundtheworldandImthinkingaboutreconfiguringthefollowingaspects
ImplementaninterfacedesignsimilartodatabasesqldriverinordertofacilitateCRUDoperationsImplementrelationaldatabaseassociationslikeonetooneonetomanyandmanytomanyHeresasample
typeProfilestruct
Nicknamestring
Mobilestring
typeUserinfostruct
Uidint
PK_Usernamestring
Departnamestring
CreatedtimeTime
ProfileHasOne
Auto-createtablesandindexesImplementaconnectionpoolusinggoroutines
LinksDirectoryPrevioussectionPostgreSQLNextsectionNoSQLdatabase
HowtousebeedbORM
130
56NoSQLdatabaseANoSQLdatabaseprovidesamechanismforthestorageandretrievalofdatathatuseslooserconsistencymodelsthantypicalrelationaldatabasesinordertoachievehorizontalscalingandhigheravailabilitySomeauthorsrefertothemasNotonlySQLtoemphasizethatsomeNoSQLsystemsdoallowSQL-likequerylanguagestobeused
AstheClanguageofthe21stcenturyGohasgoodsupportforNoSQLdatabasesincludingthepopularredismongoDBCassandraandMembaseNoSQLdatabases
redisredisisakey-valuestoragesystemlikeMemcachedthatsupportsthestringlistsetandzset(orderedset)valuetypes
TherearesomeGodatabasedriversforredis
httpsgithubcomgaryburdredigohttpsgithubcomgo-redisredishttpsgithubcomhoisieredishttpsgithubcomalphazeroGo-Redishttpsgithubcomsimonz05godis
Letsseehowtousethedriverthatredigotooperateonadatabase
packagemain
import(
fmt
githubcomgaryburdredigoredis
os
ossignal
syscall
time
)
var(
PoolredisPool
)
funcinit()
redisHost=6379
Pool=newPool(redisHost)
close()
funcnewPool(serverstring)redisPool
returnampredisPool
MaxIdle3
IdleTimeout240timeSecond
Dialfunc()(redisConnerror)
cerr=redisDial(tcpserver)
iferr=nil
returnnilerr
returncerr
TestOnBorrowfunc(credisConnttimeTime)error
_err=cDo(PING)
returnerr
NOSQL
131
funcclose()
c=make(chanosSignal1)
signalNotify(cosInterrupt)
signalNotify(csyscallSIGTERM)
signalNotify(csyscallSIGKILL)
gofunc()
lt-c
PoolClose()
osExit(0)
()
funcGet(keystring)([]byteerror)
conn=PoolGet()
deferconnClose()
vardata[]byte
dataerr=redisBytes(connDo(GETkey))
iferr=nil
returndatafmtErrorf(errorgetkeysvkeyerr)
returndataerr
funcmain()
testerr=Get(test)
fmtPrintln(testerr)
IforkedthelastofthesepackagesfixedsomebugsanduseditinmyshortURLservice(2millionPVeveryday)
httpsgithubcomastaxiegoredis
LetsseehowtousethedriverthatIforkedtooperateonadatabase
packagemain
import(
githubcomastaxiegoredis
fmt
)
funcmain()
varclientgoredisClient
SetthedefaultportinRedis
clientAddr=1270016379
stringmanipulation
clientSet(a[]byte(hello))
val_=clientGet(a)
fmtPrintln(string(val))
clientDel(a)
listoperation
vals=[]stringabcde
for_v=rangevals
clientRpush(l[]byte(v))
dbvals_=clientLrange(l04)
foriv=rangedbvals
println(istring(v))
clientDel(l)
NOSQL
132
WecanseethatitisquiteeasytooperateredisinGoandithashighperformanceItsclientcommandsarealmostthesameasredisbuilt-incommands
mongoDBmongoDB(fromhumongous)isanopensourcedocument-orienteddatabasesystemdevelopedandsupportedby10genItispartoftheNoSQLfamilyofdatabasesystemsInsteadofstoringdataintablesasisdoneinaclassicalrelationaldatabaseMongoDBstoresstructureddataasJSON-likedocumentswithdynamicschemas(MongoDBcallstheformatBSON)makingtheintegrationofdataincertaintypesofapplicationseasierandfaster
Figure51MongoDBcomparedtoMysql
ThebestdriverformongoDBiscalledmgoanditispossiblethatitwillbeincludedinthestandardlibraryinthefuture
Installmgo
gogetgopkginmgov2
Hereistheexample
packagemain
import(
fmt
gopkginmgov2
gopkginmgov2bson
log
)
typePersonstruct
Namestring
Phonestring
funcmain()
sessionerr=mgoDial(server1examplecomserver2examplecom)
iferr=nil
panic(err)
defersessionClose()
OptionalSwitchthesessiontoamonotonicbehavior
sessionSetMode(mgoMonotonictrue)
c=sessionDB(test)C(people)
err=cInsert(ampPersonAle+555381169639
ampPersonCla+555384028510)
iferr=nil
logFatal(err)
result=Person
err=cFind(bsonMnameAle)One(ampresult)
iferr=nil
logFatal(err)
fmtPrintln(PhoneresultPhone)
NOSQL
133
WecanseethattherearenobigdifferenceswhenitcomestooperatingonmgoorbeedbdatabasestheyarebothbasedonstructsThisistheGowayofdoingthings
LinksDirectoryPrevioussectionDevelopORMbasedonbeedbNextsectionSummary
NOSQL
134
57SummaryInthischapteryoufirstlearnedaboutthedesignofthedatabasesqlinterfaceandmanythird-partydatabasedriversforvariousdatabasetypesThenIintroducedbeedbanORMforrelationaldatabasestoyouIalsoshowedyousomesampledatabaseoperationsIntheendItalkedaboutafewNoSQLdatabasesWesawthatGoprovidesverygoodsupportforthoseNoSQLdatabases
AfterreadingthischapterIhopethatyouhaveabetterunderstandingofhowtooperatedatabasesinGoThisisthemostimportantpartofwebdevelopmentsoIwantyoutocompletelyunderstandthedesignconceptsofthedatabasesqlinterface
LinksDirectoryPrevioussectionNoSQLdatabaseNextsectionDatastorageandsession
Summary
135
6DatastorageandsessionsAnimportanttopicinwebdevelopmentisprovidingagooduserexperiencebutthefactthatHTTPisastatelessprotocolseemscontrarytothisspiritHowcanwecontrolthewholeprocessofviewingwebsitesforusersTheclassicsolutionsareusingcookiesandsessionswherecookiesserveastheclientsidemechanismandsessionsaresavedontheserversidewithauniqueidentifierforeverysingleuserNotethatsessionscanbepassedinURLsorcookiesoreveninyourdatabase(whichismuchmoresecurebutmayhamperyourapplicationperformance)
Insection61wearegoingtotalkaboutdifferencesbetweencookiesandsessionsInsection62youlllearnhowtousesessionsinGowithanimplementationofasessionmanagerInsection63wewilltalkaboutsessionhijackingandhowtopreventitwhenyouknowthatsessionscanbesavedanywhereThesessionmanagerwewillimplementinsection63willsavesessionsinmemorybutifweneedtoexpandourapplicationtoallowforsessionsharingitsalwaysbettertosavethesesessionsdirectlyintoourdatabaseWelltalkmoreaboutthisinsection64
LinksDirectoryPreviousChapterChapter5SummaryNextsectionSessionandcookies
Datastorageandsession
136
61SessionandcookiesSessionsandcookiesaretwoverycommonwebconceptsandarealsoveryeasytomisunderstandHowevertheyareextremelyimportantfortheauthorizationofpagesaswellasforgatheringpagestatisticsLetstakealookatthesetwousecases
SupposeyouwanttocrawlapagethatrestrictspublicaccesslikeatwitterusershomepageforinstanceOfcourseyoucanopenyourbrowserandtypeinyourusernameandpasswordtologinandaccessthatinformationbutso-calledwebcrawlingmeansthatweuseaprogramtoautomatethisprocesswithoutanyhumaninterventionThereforewehavetofindoutwhatisreallygoingonbehindthesceneswhenweuseabrowsertologin
WhenwefirstreceivealoginpageandtypeinausernameandpasswordafterwepresstheloginbuttonthebrowsersendsaPOSTrequesttotheremoteserverTheBrowserredirectstotheuserhomepageaftertheserververifiesthelogininformationandreturnsanHTTPresponseThequestionhereishowdoestheserverknowthatwehaveaccessprivilegesforthedesiredwebpageBecauseHTTPisstatelesstheserverhasnowayofknowingwhetherornotwepassedtheverificationinlaststepTheeasiestandperhapsthemostnaivesolutionistoappendtheusernameandpasswordtotheURLThisworksbutputstoomuchpressureontheserver(theservermustvalidateeveryrequestagainstthedatabase)andcanbedetrimentaltotheuserexperienceAnalternativewayofachievingthisgoalistosavetheusersidentityeitherontheserversideorclientsideusingcookiesandsessions
Cookiesinshortstorehistoricalinformation(includinguserlogininformation)ontheclientscomputerTheclientsbrowsersendsthesecookieseverytimetheuservisitsthesamewebsiteautomaticallycompletingtheloginstepfortheuser
Figure61cookieprinciple
SessionsontheotherhandstorehistoricalinformationontheserversideTheserverusesasessionidtoidentifydifferentsessionsandthesessionidthatisgeneratedbytheservershouldalwaysberandomanduniqueYoucanusecookiesorURLargumentstogettheclientsidentity
Figure62sessionprinciple
CookiesCookiesaremaintainedbybrowsersTheycanbemodifiedduringcommunicationbetweenwebserversandbrowsersWebapplicationscanaccesscookieinformationwhenusersvisitthecorrespondingwebsitesWithinmostbrowsersettingsthereisonesettingpertainingtocookieprivacyYoushouldbeabletoseesomethingsimilartothefollowingwhenyouopenit
Figure63cookieinbrowsers
Cookieshaveanexpirytimeandtherearetwotypesofcookiesdistinguishedbytheirlifecylessessioncookiesandpersistentcookies
IfyourapplicationdoesntsetacookieexpirytimethebrowserwillnotsaveitintothelocalfilesystemafterthebrowserisclosedThesecookiesarecalledsessioncookiesandthistypeofcookieisusuallysavedinmemoryinsteadoftothelocalfilesystem
Ifyourapplicationdoessetanexpirytime(forexamplesetMaxAge(606024))thebrowserwillsavethiscookietothelocalfilesystemanditwillnotbedeleteduntilreachingtheallottedexpirytimeCookiesthataresavedtothelocalfilesystemcanbesharedbydifferentbrowserprocesses-forexamplebytwoIEwindowsdifferentbrowsersusedifferentprocessesfordealingwithcookiesthataresavedinmemory
Sessionandcookies
137
SetcookiesinGoGousestheSetCookiefunctioninthenethttppackagetosetcookies
httpSetCookie(wResponseWritercookieCookie)
wistheresponseoftherequestandcookieisastructLetsseewhatitlookslike
typeCookiestruct
Namestring
Valuestring
Pathstring
Domainstring
ExpirestimeTime
RawExpiresstring
MaxAge=0meansnoMax-Ageattributespecified
MaxAgelt0meansdeletecookienowequivalentlyMax-Age0
MaxAgegt0meansMax-Ageattributepresentandgiveninseconds
MaxAgeint
Securebool
HttpOnlybool
Rawstring
Unparsed[]stringRawtextofunparsedattribute-valuepairs
Hereisanexampleofsettingacookie
expiration=timeNow()Add(36524timeHour)
cookie=httpCookieNameusernameValueastaxieExpiresexpiration
httpSetCookie(wampcookie)
FetchcookiesinGoTheaboveexampleshowshowtosetacookieNowletsseehowtogetacookiethathasbeenset
cookie_=rCookie(username)
fmtFprint(wcookie)
Hereisanotherwaytogetacookie
for_cookie=rangerCookies()
fmtFprint(wcookieName)
Asyoucanseeitsveryconvenienttogetcookiesfromrequests
SessionsAsessionisaseriesofactionsormessagesForexampleyoucanthinkoftheactionsyoubetweenpickingupyourtelephonetohanginguptobeatypeofsessionWhenitcomestonetworkprotocolssessionshavemoretodowithconnectionsbetweenbrowsersandservers
Sessionshelptostoretheconnectionstatusbetweenserverandclientandthiscansometimesbeintheformofadatastoragestruct
Sessionandcookies
138
Sessionsareaserver-sidemechanismandusuallyemployhashtables(orsomethingsimilar)tosaveincominginformation
WhenanapplicationneedstoassignanewsessiontoaclienttheservershouldcheckifthereareanyexistingsessionsforthesameclientwithauniquesessionidIfthesessionidalreadyexiststheserverwilljustreturnthesamesessiontotheclientOntheotherhandifasessioniddoesntexistfortheclienttheservercreatesabrandnewsession(thisusuallyhappenswhentheserverhasdeletedthecorrespondingsessionidbuttheuserhasappendedtheoldsessionmanually)
Thesessionitselfisnotcomplexbutitsimplementationanddeploymentaresoyoucannotuseonewaytorulethemall
SummaryInconclusionthepurposeofsessionsandcookiesarethesameTheyarebothforovercomingthestatelessnessofHTTPbuttheyusedifferentmethodsSessionsusecookiestosavesessionidsontheclientsideandsaveallotherinformationontheserversideCookiessaveallclientinformationontheclientsideYoumayhavenoticedthatcookieshavesomesecurityproblemsForexampleusernamesandpasswordscanpotentiallybecrackedandcollectedbymaliciousthirdpartywebsites
Herearetwocommonexploits
1 appAsettinganunexpectedcookieforappB2 XSSattackappAusestheJavaScriptdocumentcookietoaccessthecookiesofappB
AfterfinishingthissectionyoushouldknowsomeofthebasicconceptsofcookiesandsessionsYoushouldbeabletounderstandthedifferencesbetweenthemsothatyouwontkillyourselfwhenbugsinevitablyemergeWelldiscusssessionsinmoredetailinthefollowingsections
LinksDirectoryPrevioussectionDatastorageandsessionNextsectionHowtousesessioninGo
Sessionandcookies
139
62HowtousesessionsinGoInsection61welearnedthatsessionsareonesolutionforverifyingusersandthatfornowtheGostandardlibrarydoesnothavebaked-insupportforsessionsorsessionhandlingSoweregoingtoimplementourownversionofasessionmanagerinGo
CreatingsessionsThebasicprinciplebehindsessionsisthataservermaintainsinformationforeverysingleclientandclientsrelyonuniquesessionidstoaccessthisinformationWhenusersvisitthewebapplicationtheserverwillcreateanewsessionwiththefollowingthreestepsasneeded
CreateauniquesessionidOpenupadatastoragespacenormallywesavesessionsinmemorybutyouwillloseallsessiondataifthesystemisaccidentallyinterruptedThiscanbeaveryseriousissueifwebapplicationdealswithsensitivedatalikeinelectroniccommerceforinstanceInordertosolvethisproblemyoucaninsteadsaveyoursessiondatainadatabaseorfilesystemThismakesdatapersistencemorereliableandeasytosharewithotherapplicationsalthoughthetradeoffisthatmoreserver-sideIOisneededtoreadandwritethesesessionsSendtheuniquesessionidtotheclient
ThekeystephereistosendtheuniquesessionidtotheclientInthecontextofastandardHTTPresponseyoucaneitherusetheresponselineheaderorbodytoaccomplishthisthereforewehavetwowaystosendsessionidstoclientsbycookiesorURLrewrites
CookiestheservercaneasilyuseSet-cookieinsideofaresponseheadertosendasessionidtoaclientandaclientcanthenusethiscookieforfuturerequestsweoftensettheexpirytimeforcookiescontainingsessioninformationto0whichmeansthecookiewillbesavedinmemoryandonlydeletedafterusershaveclosetheirbrowsersURLrewriteappendthesessionidasargumentsintheURLforallpagesThiswayseemsmessybutitsthebestchoiceifclientshavedisabledcookiesintheirbrowsers
UseGotomanagesessionsWevetalkedaboutconstructingsessionsandyoushouldnowhaveageneraloverviewofitbuthowcanweusesessionsondynamicpagesLetstakeacloserlookatthelifecycleofasessionsowecancontinueimplementingourGosessionmanager
Sessionmanagementdesign
Hereisalistofsomeofthekeyconsiderationsinsessionmanagementdesign
GlobalsessionmanagerKeepsessioniduniqueHaveonesessionforeveryuserSessionstorageinmemoryfileordatabaseDealwithexpiredsessions
NextwellexamineacompleteexampleofaGosessionmanagerandtherationalebehindsomeofitsdesigndecisions
Sessionmanager
Defineaglobalsessionmanager
HowtousesessioninGo
140
typeManagerstruct
cookieNamestringprivatecookiename
locksyncMutexprotectssession
providerProvider
maxlifetimeint64
funcNewManager(provideNamecookieNamestringmaxlifetimeint64)(Managererror)
providerok=provides[provideName]
ifok
returnnilfmtErrorf(sessionunknownprovideq(forgottenimport)provideName)
returnampManagerproviderprovidercookieNamecookieNamemaxlifetimemaxlifetimenil
Createaglobalsessionmanagerinthemain()function
varglobalSessionssessionManager
Theninitializethesessionmanager
funcinit()
globalSessions=NewManager(memorygosessionid3600)
WeknowthatwecansavesessionsinmanywaysincludinginmemorythefilesystemordirectlyintothedatabaseWeneedtodefineaProviderinterfaceinordertorepresenttheunderlyingstructureofoursessionmanager
typeProviderinterface
SessionInit(sidstring)(Sessionerror)
SessionRead(sidstring)(Sessionerror)
SessionDestroy(sidstring)error
SessionGC(maxLifeTimeint64)
SessionInitimplementstheinitializationofasessionandreturnsanewsessionifitsucceedsSessionReadreturnsasessionrepresentedbythecorrespondingsidCreatesanewsessionandreturnsitifitdoesnotalreadyexistSessionDestroygivenansiddeletesthecorrespondingsessionSessionGCdeletesexpiredsessionvariablesaccordingtomaxLifeTime
SowhatmethodsshouldoursessioninterfacehaveIfyouhaveanyexperienceinwebdevelopmentyoushouldknowthatthereareonlyfouroperationsforsessionssetvaluegetvaluedeletevalueandgetcurrentsessionidSooursessioninterfaceshouldhavefourmethodstoperformtheseoperations
typeSessioninterface
Set(keyvalueinterface)errorsetsessionvalue
Get(keyinterface)interfacegetsessionvalue
Delete(keyinterface)errordeletesessionvalue
SessionID()stringbackcurrentsessionID
ThisdesigntakesitsrootsfromthedatabasesqldriverwhichdefinestheinterfacefirstthenregistersspecificstructureswhenwewanttouseitThefollowingcodeistheinternalimplementationofasessionregisterfunction
HowtousesessioninGo
141
varprovides=make(map[string]Provider)
Registermakesasessionprovideravailablebytheprovidedname
IfaRegisteriscalledtwicewiththesamenameorifthedriverisnil
itpanics
funcRegister(namestringproviderProvider)
ifprovider==nil
panic(sessionRegisterproviderisnil)
if_dup=provides[name]dup
panic(sessionRegistercalledtwiceforprovider+name)
provides[name]=provider
UniquesessionidsSessionidsareforidentifyingusersofwebapplicationssotheymustbeuniqueThefollowingcodeshowshowtoachievethisgoal
func(managerManager)sessionId()string
b=make([]byte32)
if_err=ioReadFull(randReaderb)err=nil
return
returnbase64URLEncodingEncodeToString(b)
CreatingasessionWeneedtoallocateorgetanexistingsessioninordertovalidateuseroperationsTheSessionStartfunctionisforcheckingtheexistenceofanysessionsrelatedtothecurrentuserandcreatinganewsessionifnoneisfound
func(managerManager)SessionStart(whttpResponseWriterrhttpRequest)(sessionSession)
managerlockLock()
defermanagerlockUnlock()
cookieerr=rCookie(managercookieName)
iferr=nil||cookieValue==
sid=managersessionId()
session_=managerproviderSessionInit(sid)
cookie=httpCookieNamemanagercookieNameValueurlQueryEscape(sid)PathHttpOnlytrueM
axAgeint(managermaxlifetime)
httpSetCookie(wampcookie)
else
sid_=urlQueryUnescape(cookieValue)
session_=managerproviderSessionRead(sid)
return
Hereisanexamplethatusessessionsforaloginoperation
funclogin(whttpResponseWriterrhttpRequest)
sess=globalSessionsSessionStart(wr)
rParseForm()
ifrMethod==GET
t_=templateParseFiles(logingtpl)
wHeader()Set(Content-Typetexthtml)
tExecute(wsessGet(username))
else
sessSet(usernamerForm[username])
httpRedirect(wr302)
HowtousesessioninGo
142
Operationvaluesetgetanddelete
TheSessionStartfunctionreturnsavariablethatimplementsasessioninterfaceHowdoweuseit
YousawsessionGet(uid)intheaboveexampleforabasicoperationNowletsexamineamoredetailedexample
funccount(whttpResponseWriterrhttpRequest)
sess=globalSessionsSessionStart(wr)
createtime=sessGet(createtime)
ifcreatetime==nil
sessSet(createtimetimeNow()Unix())
elseif(createtime(int64)+360)lt(timeNow()Unix())
globalSessionsSessionDestroy(wr)
sess=globalSessionsSessionStart(wr)
ct=sessGet(countnum)
ifct==nil
sessSet(countnum1)
else
sessSet(countnum(ct(int)+1))
t_=templateParseFiles(countgtpl)
wHeader()Set(Content-Typetexthtml)
tExecute(wsessGet(countnum))
AsyoucanseeoperatingonsessionssimplyinvolvesusingthekeyvaluepatternintheSetGetandDeleteoperations
BecausesessionshavetheconceptofanexpirytimewedefinetheGCtoupdatethesessionslatestmodifytimeThiswaytheGCwillnotdeletesessionsthathaveexpiredbutarestillbeingused
ResetsessionsWeknowthatwebapplicationshavealogoutoperationWhenuserslogoutweneedtodeletethecorrespondingsessionWevealreadyusedtheresetoperationinaboveexample-nowletstakealookatthefunctionbody
Destroysessionid
func(managerManager)SessionDestroy(whttpResponseWriterrhttpRequest)
cookieerr=rCookie(managercookieName)
iferr=nil||cookieValue==
return
else
managerlockLock()
defermanagerlockUnlock()
managerproviderSessionDestroy(cookieValue)
expiration=timeNow()
cookie=httpCookieNamemanagercookieNamePathHttpOnlytrueExpiresexpirationMaxAge-1
httpSetCookie(wampcookie)
Deletesessions
LetsseehowtoletthesessionmanagerdeleteasessionWeneedtostarttheGCinthemain()function
HowtousesessioninGo
143
funcinit()
goglobalSessionsGC()
func(managerManager)GC()
managerlockLock()
defermanagerlockUnlock()
managerproviderSessionGC(managermaxlifetime)
timeAfterFunc(timeDuration(managermaxlifetime)func()managerGC())
WeseethattheGCmakesfulluseofthetimerfunctioninthetimepackageItautomaticallycallsGCwhenthesessiontimesoutensuringthatallsessionsareusableduringmaxLifeTimeAsimilarsolutioncanbeusedtocountonlineusers
SummarySofarweimplementedasessionmanagertomanageglobalsessionsinthewebapplicationanddefinedtheProviderinterfaceasthestorageimplementationofSessionInthenextsectionwearegoingtotalkabouthowtoimplementProviderforadditionalsessionstoragestructureswhichyouwillbeabletoreferenceinthefuture
LinksDirectoryPrevioussectionSessionandcookiesNextsectionSessionstorage
HowtousesessioninGo
144
63SessionstorageWeintroducedasimplesessionmanagersworkingprinciplesintheprevioussectionandamongotherthingswedefinedasessionstorageinterfaceInthissectionImgoingtoshowyouanexampleofamemorybasedsessionstorageenginethatimplementsthisinterfaceYoucantailorthistootherformsofsessionstorageaswell
packagememory
import(
containerlist
githubcomastaxiesession
sync
time
)
varpder=ampProviderlistlistNew()
typeSessionStorestruct
sidstringuniquesessionid
timeAccessedtimeTimelastaccesstime
valuemap[interface]interfacesessionvaluestoredinside
func(stSessionStore)Set(keyvalueinterface)error
stvalue[key]=value
pderSessionUpdate(stsid)
returnnil
func(stSessionStore)Get(keyinterface)interface
pderSessionUpdate(stsid)
ifvok=stvalue[key]ok
returnv
else
returnnil
returnnil
func(stSessionStore)Delete(keyinterface)error
delete(stvaluekey)
pderSessionUpdate(stsid)
returnnil
func(stSessionStore)SessionID()string
returnstsid
typeProviderstruct
locksyncMutexlock
sessionsmap[string]listElementsaveinmemory
listlistListgc
func(pderProvider)SessionInit(sidstring)(sessionSessionerror)
pderlockLock()
deferpderlockUnlock()
v=make(map[interface]interface0)
newsess=ampSessionStoresidsidtimeAccessedtimeNow()valuev
element=pderlistPushBack(newsess)
pdersessions[sid]=element
returnnewsessnil
func(pderProvider)SessionRead(sidstring)(sessionSessionerror)
ifelementok=pdersessions[sid]ok
Sessionstorage
145
returnelementValue(SessionStore)nil
else
sesserr=pderSessionInit(sid)
returnsesserr
returnnilnil
func(pderProvider)SessionDestroy(sidstring)error
ifelementok=pdersessions[sid]ok
delete(pdersessionssid)
pderlistRemove(element)
returnnil
returnnil
func(pderProvider)SessionGC(maxlifetimeint64)
pderlockLock()
deferpderlockUnlock()
for
element=pderlistBack()
ifelement==nil
break
if(elementValue(SessionStore)timeAccessedUnix()+maxlifetime)lttimeNow()Unix()
pderlistRemove(element)
delete(pdersessionselementValue(SessionStore)sid)
else
break
func(pderProvider)SessionUpdate(sidstring)error
pderlockLock()
deferpderlockUnlock()
ifelementok=pdersessions[sid]ok
elementValue(SessionStore)timeAccessed=timeNow()
pderlistMoveToFront(element)
returnnil
returnnil
funcinit()
pdersessions=make(map[string]listElement0)
sessionRegister(memorypder)
TheaboveexampleimplementsamemorybasedsessionstoragemechanismItusesitsinit()functiontoregisterthisstorageenginetothesessionmanagerSohowdoweregisterthisenginefromourmainprogram
import(
githubcomastaxiesession
_githubcomastaxiesessionprovidersmemory
)
Weusetheblankimportmechanism(whichwillinvokethepackagesinit()functionautomatically)toregisterthisenginetoasessionmanagerWethenusethefollowingcodetoinitializethesessionmanager
Sessionstorage
146
varglobalSessionssessionManager
initializeininit()function
funcinit()
globalSessions_=sessionNewManager(memorygosessionid3600)
goglobalSessionsGC()
LinksDirectoryPrevioussectionHowtousesessionsinGoNextsectionPreventsessionhijacking
Sessionstorage
147
64PreventingsessionhijackingSessionhijackingisacommonyetserioussecuritythreatClientsusesessionidsforvalidationandotherpurposeswhencommunicatingwithserversUnfortunatelymaliciousthirdpartiescansometimestrackthesecommunicationsandfigureouttheclientsessionid
Inthissectionwearegoingtoshowyouhowtohijackasessionforeducationalpurposes
ThesessionhijackingprocessThefollowingcodeisacounterforthecountvariable
funccount(whttpResponseWriterrhttpRequest)
sess=globalSessionsSessionStart(wr)
ct=sessGet(countnum)
ifct==nil
sessSet(countnum1)
else
sessSet(countnum(ct(int)+1))
t_=templateParseFiles(countgtpl)
wHeader()Set(Content-Typetexthtml)
tExecute(wsessGet(countnum))
Thecontentofcountgtplisasfollows
HiNowcount
Wecanseethefollowingcontentinthebrowser
Figure64countinbrowser
Keeprefreshinguntilthenumberbecomes6thenopenthebrowserscookiemanager(Iusechromehere)Youshouldbeabletoseethefollowinginformation
Figure65cookiessavedinabrowser
Thisstepisveryimportantopenanotherbrowser(Iusefirefoxhere)copytheURLtothenewbrowseropenacookiesimulatortocreateanewcookieandinputexactlythesamevalueasthecookiewesawinourfirstbrowser
Figure66Simulateacookie
Refreshthepageandyoullseethefollowing
Figure67hijackingthesessionhassucceeded
HereweseethatwecanhijacksessionsbetweendifferentbrowsersandactionsperformedinonebrowsercanaffectthestateofapageinanotherbrowserBecauseHTTPisstatelessthereisnowayofknowingthatthesessionidfromfirefoxissimulatedandchromeisalsonotabletoknowthatitssessionidhasbeenhijacked
Preventhijackofsession
148
preventsessionhijacking
cookieonlyandtoken
ThroughthissimpleexampleofhijackingasessionyoucanseethatitsverydangerousbecauseitallowsattackerstodowhatevertheywantSohowcanwepreventsessionhijacking
ThefirststepistoonlysetsessionidsincookiesinsteadofinURLrewritesAlsoweshouldsetthehttponlycookiepropertytotrueThisrestrictsclient-sidescriptsfromgainingaccesstothesessionidUsingthesetechniquescookiescannotbeaccessedbyXSSanditwontbeaseasyaswedemonstratedtogetasessionidfromacookiemanager
ThesecondstepistoaddatokentoeveryrequestSimilartothemannerinwhichwedealtwithrepeatingformsubmissionsinprevioussectionsweaddahiddenfieldthatcontainsatokenWhenarequestissenttotheserverwecanverifythistokentoprovethattherequestisunique
h=md5New()
salt=astaxie^7amp8888
ioWriteString(hsalt+timeNow()String())
token=fmtSprintf(xhSum(nil))
ifrForm[token]=token
asktologin
sessSet(tokentoken)
SessionidtimeoutAnothersolutionistoaddacreatetimeforeverysessionandtoreplaceexpiredsessionidswithnewonesThiscanpreventsessionhijackingundercertaincircumstancessuchaswhenthehijackisattemptedtoolate
createtime=sessGet(createtime)
ifcreatetime==nil
sessSet(createtimetimeNow()Unix())
elseif(createtime(int64)+60)lt(timeNow()Unix())
globalSessionsSessionDestroy(wr)
sess=globalSessionsSessionStart(wr)
Wesetavaluetosavethecreatetimeandcheckifitsexpired(Iset60secondshere)Thisstepcanoftenthwartsessionhijackingattempts
BycombiningthetwosolutionssetoutaboveyouwillbeabletopreventmostsessionhijackingattemptsfromsucceedingOntheonehandsessionidsthatarefrequentlyresetwillresultinanattackeralwaysgettingexpiredanduselesssessionidsontheotherhandbysettingthehttponlypropertyoncookiesandensuringthatsessionidscanonlybepassedviacookiesallURLbasedattacksaremitigatedFinallywesetMaxAge=0onourcookieswhichmeansthatthesessionidswillnotbesavedinthebrowserhistory
LinksDirectoryPrevioussectionSessionstorageNextsectionSummary
Preventhijackofsession
149
65SummaryInthischapterwelearnedaboutthedefinitionandpurposeofsessionsandcookiesandtherelationshipbetweenthetwoSinceGodoesntsupportsessionsinitsstandardlibrarywealsodesignedourownsessionmanagerWewentthrougheverythingfromcreatingclientsessionstodeletingthemWethendefinedaninterfacecalledProviderwhichsupportsallsessionstoragestructuresInsection63weimplementedamemorybasedsessionmanagertopersistclientdataacrosssessionsInsection64IdemonstratedonewayofhijackingasessionThenwelookedathowtopreventyourownsessionsfrombeinghijackedIhopethatyounowunderstandmostoftheworkingprinciplesbehindsessionssothatyoureabletosafelyusetheminyourapplications
LinksDirectoryPrevioussectionPreventsessionhijackingNextchapterTextfiles
Summary
150
7TextfilesHandlingtextfilesisabigpartofwebdevelopmentWeoftenneedtoproduceorhandlereceivedtextcontentincludingstringsnumbersJSONXMLetcAsahighperformancelanguageGohasgoodsupportforthisinitsstandardlibraryYoullfindthatthesesupportinglibrariesarejustawesomeandwillallowyoutoeasilydealwithanytextcontentyoumayencounterThischaptercontains4sectionsandwillgiveyouafullintroductiontotextprocessinginGo
XMLisaninteractivelanguagethatiscommonlyusedinmanyAPIsmanywebserverswritteninJavauseXMLastheirstandardinteractionlanguageWellmoretalkaboutXMLinsection71Insection72welltakealookatJSONwhichhasbeenverypopularinrecentyearsandismuchmoreconvenientthanXMLInsection73wearegoingtotalkaboutregularexpressionswhich(forthemajorityofpeople)lookslikealanguageusedbyaliensInsection74youwillseehowtheMVCpatternisusedtodevelopapplicationsinGoandalsohowtouseGostemplatepackagefortemplatingyourviewsInsection75wellintroduceyoutofileandfolderoperationsFinallywewillexplainsomeGostringoperationsinsection76
LinksDirectoryPreviousChapterChapter6SummaryNextsectionXML
Textfiles
151
71XMLXMLisacommonlyuseddatacommunicationformatinwebservicesTodayitsassumingamoreandmoreimportantroleinwebdevelopmentInthissectionweregoingtointroducehowtoworkwithXMLthroughGosstandardlibrary
IwillnotmakeanyattemptstoteachXMLssyntaxorconventionsForthatpleasereadmoredocumentationaboutXMLitselfWewillonlyfocusonhowtoencodeanddecodeXMLfilesinGo
SupposeyouworkinITandyouhavetodealwiththefollowingXMLconfigurationfile
ltxmlversion=10encoding=utf-8gt
ltserversversion=1gt
ltservergt
ltserverNamegtShanghai_VPNltserverNamegt
ltserverIPgt127001ltserverIPgt
ltservergt
ltservergt
ltserverNamegtBeijing_VPNltserverNamegt
ltserverIPgt127002ltserverIPgt
ltservergt
ltserversgt
TheaboveXMLdocumentcontainstwokindsofinformationaboutyourservertheservernameandIPWewillusethisdocumentinourfollowingexamples
ParseXMLHowdoweparsethisXMLdocumentWecanusetheUnmarshalfunctioninGosxmlpackagetodothis
funcUnmarshal(data[]bytevinterface)error
thedataparameterreceivesadatastreamfromanXMLsourceandvisthestructureyouwanttooutputtheparsedXMLtoItisaninterfacewhichmeansyoucanconvertXMLtoanystructureyoudesireHerewellonlytalkabouthowtoconvertfromXMLtothestructtypesincetheysharesimilartreestructures
Samplecode
XML
152
packagemain
import(
encodingxml
fmt
ioioutil
os
)
typeRecurlyserversstruct
XMLNamexmlName`xmlservers`
Versionstring`xmlversionattr`
Svs[]server`xmlserver`
Descriptionstring`xmlinnerxml`
typeserverstruct
XMLNamexmlName`xmlserver`
ServerNamestring`xmlserverName`
ServerIPstring`xmlserverIP`
funcmain()
fileerr=osOpen(serversxml)Forreadaccess
iferr=nil
fmtPrintf(errorverr)
return
deferfileClose()
dataerr=ioutilReadAll(file)
iferr=nil
fmtPrintf(errorverr)
return
v=Recurlyservers
err=xmlUnmarshal(dataampv)
iferr=nil
fmtPrintf(errorverr)
return
fmtPrintln(v)
XMLisactuallyatreedatastructureandwecandefineaverysimilarstructureusingstructsinGothenusexmlUnmarshaltoconvertfromXMLtoourstructobjectThesamplecodewillprintthefollowingcontent
servers1[serverShanghai_VPN127001serverBeijing_VPN127002]
ltservergt
ltserverNamegtShanghai_VPNltserverNamegt
ltserverIPgt127001ltserverIPgt
ltservergt
ltservergt
ltserverNamegtBeijing_VPNltserverNamegt
ltserverIPgt127002ltserverIPgt
ltservergt
WeusexmlUnmarshaltoparsetheXMLdocumenttothecorrespondingstructobjectYoushouldseethatwehavesomethinglikexmlserverNameinourstructThisisafeatureofstructscalledstructtagsforhelpingwithreflectionLetsseethedefinitionofUnmarshalagain
funcUnmarshal(data[]bytevinterface)error
XML
153
ThefirstargumentisanXMLdatastreamThesecondargumentisstoragetypeandsupportsthestructsliceandstringtypesGosXMLpackageusesreflectionfordatamappingsoallfieldsinvshouldbeexportedHoweverthiscausesaproblemhowdoesitknowwhichXMLfieldcorrespondstothemappedstructfieldTheansweristhattheXMLparserparsesdatainacertainorderThelibrarywilltrytofindthematchingstructtagfirstIfamatchcannotbefoundthenitsearchesthroughthestructfieldnamesBeawarethatalltagsfieldnamesandXMLelementsarecasesensitivesoyouhavetomakesurethatthereisaone-to-onecorrespondenceforthemappingtosucceed
GosreflectionmechanismallowsyoutousethistaginformationtoreflectXMLdatatoastructobjectIfyouwanttoknowmoreaboutreflectioninGopleasereadthepackagedocumentationonstructtagsandreflection
HerearesomeruleswhenusingthexmlpackagetoparseXMLdocumentstostructs
Ifthefieldtypeisastringor[]bytewiththetaginnerxmlUnmarshalwillassignrawXMLdatatoitlikeDescriptionintheaboveexample
Shanghai_VPN127001Beijing_VPN127002
IfafieldiscalledXMLNameanditstypeisxmlNamethenitgetstheelementnamelikeserversinaboveexample
IfafieldstagcontainsthecorrespondingelementnamethenitgetstheelementnameaswelllikeservernameandserveripintheaboveexampleIfafieldstagcontainsattrthenitgetsthecorrespondingelementsattributelikeversioninaboveexampleIfafieldstagcontainssomethinglikeagtbgtcitgetsthevalueoftheelementcofnodebofnodeaIfafieldstagcontains=thenitgetsnothingIfafieldstagcontainsanythenitgetsallchildelementswhichdonotfittheotherrulesIftheXMLelementshaveoneormorecommentsallofthesecommentswillbeaddedtothefirstfieldthathasthetagthatcontainscommentsThisfieldtypecanbeastringor[]byteIfthiskindoffielddoesnotexistallcommentsarediscarded
TheserulestellyouhowtodefinetagsinstructsOnceyouunderstandtheserulesmappingXMLtostructswillbeaseasyasthesamplecodeaboveBecausetagsandXMLelementshaveaone-to-onecorrespondencewecanalsouseslicestorepresentmultipleelementsonthesamelevel
Notethatallfieldsinstructsshouldbeexported(capitalized)inordertoparsedatacorrectly
ProduceXMLWhatifwewanttoproduceanXMLdocumentinsteadofparsingoneHowdowedothisinGoUnsurprisinglythexmlpackageprovidestwofunctionswhichareMarshalandMarshalIndentwherethesecondfunctionautomaticallyindentsthemarshalledXMLdocumentTheirdefinitionasfollows
funcMarshal(vinterface)([]byteerror)
funcMarshalIndent(vinterfaceprefixindentstring)([]byteerror)
ThefirstargumentinbothofthesefunctionsisforstoringamarshalledXMLdatastream
Letslookatanexampletoseehowthisworks
XML
154
packagemain
import(
encodingxml
fmt
os
)
typeServersstruct
XMLNamexmlName`xmlservers`
Versionstring`xmlversionattr`
Svs[]server`xmlserver`
typeserverstruct
ServerNamestring`xmlserverName`
ServerIPstring`xmlserverIP`
funcmain()
v=ampServersVersion1
vSvs=append(vSvsserverShanghai_VPN127001)
vSvs=append(vSvsserverBeijing_VPN127002)
outputerr=xmlMarshalIndent(v)
iferr=nil
fmtPrintf(errorvnerr)
osStdoutWrite([]byte(xmlHeader))
osStdoutWrite(output)
Theaboveexampleprintsthefollowinginformation
ltxmlversion=10encoding=UTF-8gt
ltserversversion=1gt
ltservergt
ltserverNamegtShanghai_VPNltserverNamegt
ltserverIPgt127001ltserverIPgt
ltservergt
ltservergt
ltserverNamegtBeijing_VPNltserverNamegt
ltserverIPgt127002ltserverIPgt
ltservergt
ltserversgt
AswevepreviouslydefinedthereasonwehaveosStdoutWrite([]byte(xmlHeader))isbecausebothxmlMarshalIndentandxmlMarshaldonotoutputXMLheadersontheirownsowehavetoexplicitlyprinttheminordertoproduceXMLdocumentscorrectly
HerewecanseethatMarshalalsoreceivesavparameteroftypeinterfaceSowhataretheruleswhenmarshallingtoanXMLdocument
IfvisanarrayorsliceitprintsallelementslikeavalueIfvisapointeritprintsthecontentthatvispointingtoprintingnothingwhenvisnilIfvisainterfaceitdealwiththeinterfaceaswellIfvisoneoftheothertypesitprintsthevalueofthattype
SohowdoesxmlMarshaldecidetheelementsnameItfollowstheensuingrules
IfvisastructitdefinesthenameinthetagofXMLNameThefieldnameisXMLNameandthetypeisxmlNameFieldtaginstructFieldnameinstructTypenameofmarshal
XML
155
ThenweneedtofigureouthowtosettagsinordertoproducethefinalXMLdocument
XMLNamewillnotbeprintedFieldsthathavetagscontaining-willnotbeprintedIfatagcontainsnameattritusesnameastheattributenameandthefieldvalueasthevaluelikeversionintheaboveexampleIfatagcontainsattritusesthefieldsnameastheattributenameandthefieldvalueasitsvalueIfatagcontainschardataitprintscharacterdatainsteadofelementIfatagcontainsinnerxmlitprintstherawvalueIfatagcontainscommentitprintsitasacommentwithoutescapingsoyoucannothave--initsvalueIfatagcontainsomitemptyitomitsthisfieldifitsvalueiszero-valueincludingfalse0nilpointerornilinterfacezerolengthofarrayslicemapandstringIfatagcontainsagtbgtcitprintsthreeelementswhereacontainsbandbcontainsclikeinthefollowingcode `xmlFirstNamestringxmlnamegtfirstLastNamestringxmlnamegtlast`
Asta
Xieltnamegt```YoumayhavenoticedthatstructtagsareveryusefulfordealingwithXMLandthesamegoesfortheotherdataformatswellbediscussinginthefollowingsectionsIfyoustillfindthatyouhaveproblemswithworkingwithstructtagsyoushouldprobablyreadmoredocumentationaboutthembeforedivingintothenextsection
LinksDirectoryPrevioussectionTextfilesNextsectionJSON
XML
156
72JSONJSON(JavaScriptObjectNotation)isalightweightdataexchangelanguagewhichisbasedontextdescriptionItsadvantagesincludebeingself-descriptiveeasytounderstandetcEventhoughitisasubsetofJavaScriptJSONusesadifferenttextformattheresultbeingthatitcanbeconsideredasanindependentlanguageJSONbearssimilaritytoC-familylanguages
ThebiggestdifferencebetweenJSONandXMListhatXMLisacompletemarkuplanguagewhereasJSONisnotJSONissmallerandfasterthanXMLthereforeitsmucheasierandquickertoparseinbrowserswhichisoneofthereasonswhymanyopenplatformschoosetouseJSONastheirdataexchangeinterfacelanguage
SinceJSONisbecomingmoreandmoreimportantinwebdevelopmentletstakealookatthelevelofsupportGohasforJSONYoullfindthatGosstandardlibraryhasverygoodsupportforencodinganddecodingJSON
HereweuseJSONtorepresenttheexampleintheprevioussection
servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP127002]
TherestofthissectionwillusethisJSONdatatointroduceJSONconceptsinGo
ParseJSON
Parsetostruct
SupposewehavetheJSONintheaboveexampleHowcanweparsethisdataandmapittoastructinGoGoprovidesthefollowingfunctionforjustthispurpose
funcUnmarshal(data[]bytevinterface)error
Wecanusethisfunctionlikeso
packagemain
import(
encodingjson
fmt
)
typeServerstruct
ServerNamestring
ServerIPstring
typeServerslicestruct
Servers[]Server
funcmain()
varsServerslice
str=`servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP
127002]`
jsonUnmarshal([]byte(str)amps)
fmtPrintln(s)
JSON
157
IntheaboveexamplewedefinedacorrespondingstructsinGoforourJSONusingsliceforanarrayofJSONobjectsandfieldnameasourJSONkeysButhowdoesGoknowwhichJSONobjectcorrespondstowhichspecificstructfiledSupposewehaveakeycalledFooinJSONHowdowefinditscorrespondingfield
FirstGotriestofindthe(capitalised)exportedfieldwhosetagcontainsFooIfnomatchcanbefoundlookforthefieldwhosenameisFooIftherearestillnotmatcheslookforsomethinglikeFOOorFoOignoringcasesensitivity
YoumayhavenoticedthatallfieldsthataregoingtobeassignedshouldbeexportedandGoonlyassignsfieldsthatcanbefoundignoringallothersThiscanbeusefulifyouneedtodealwithlargechunksofJSONdatabutyouonlyaspecificsubsetofitthedatayoudontneedcaneasilybediscarded
ParsetointerfaceWhenweknowwhatkindofJSONtoexpectinadvancewecanparseittoaspecificstructButwhatifwedontknow
WeknowthataninterfacecanbeanythinginGosoitisthebestcontainertosaveourJSONofunknownformatTheJSONpackageusesmap[string]interfaceand[]interfacetosaveallkindsofJSONobjectsandarraysHereisalistofJSONmappingrelations
boolrepresentsJSONbooleansfloat64representsJSONnumbersstringrepresentsJSONstringsnilrepresentsJSONnull
SupposewehavethefollowingJSONdata
b=[]byte(`NameWednesdayAge6Parents[GomezMorticia]`)
NowweparsethisJSONtoaninterface
varfinterface
err=jsonUnmarshal(bampf)
Thefstoresamapwherekeysarestringsandvaluesareinterfaces
f=map[string]interface
NameWednesday
Age6
Parents[]interface
Gomez
Morticia
SohowdoweaccessthisdataTypeassertion
m=f(map[string]interface)
Afterassertedyoucanusethefollowingcodetoaccessdata
JSON
158
forkv=rangem
switchvv=v(type)
casestring
fmtPrintln(kisstringvv)
caseint
fmtPrintln(kisintvv)
casefloat64
fmtPrintln(kisfloat64vv)
case[]interface
fmtPrintln(kisanarray)
foriu=rangevv
fmtPrintln(iu)
default
fmtPrintln(kisofatypeIdontknowhowtohandle)
AsyoucanseewecannowparseJSONofanunknownformatthroughinterfaceandtypeassertion
TheaboveexampleistheofficialsolutionbuttypeassertingisnotalwaysconvenientSoIrecommendanopensourceprojectcalledsimplejsoncreatedandmaintainedbybitlyHereisanexampleofhowtousethisprojecttodealwithJSONofanunknownformat
jserr=NewJson([]byte(`
test
array[123]
int10
float5150
bignum9223372036854775807
stringsimplejson
booltrue
`))
arr_=jsGet(test)Get(array)Array()
i_=jsGet(test)Get(int)Int()
ms=jsGet(test)Get(string)MustString()
ItsnothardtoseehowconvenientthisisCheckouttherepositorytoseemoreinformationhttpsgithubcombitlygo-simplejson
ProducingJSONInmanysituationsweneedtoproduceJSONdataandrespondtoclientsInGotheJSONpackagehasafunctioncalledMarshaltodojustthat
funcMarshal(vinterface)([]byteerror)
SupposeweneedtoproduceaserverinformationlistWehavefollowingsample
JSON
159
packagemain
import(
encodingjson
fmt
)
typeServerstruct
ServerNamestring
ServerIPstring
typeServerslicestruct
Servers[]Server
funcmain()
varsServerslice
sServers=append(sServersServerServerNameShanghai_VPNServerIP127001)
sServers=append(sServersServerServerNameBeijing_VPNServerIP127002)
berr=jsonMarshal(s)
iferr=nil
fmtPrintln(jsonerrerr)
fmtPrintln(string(b))
Output
Servers[ServerNameShanghai_VPNServerIP127001ServerNameBeijing_VPNServerIP127002]
AsyouknowallfieldnamesarecapitalizedbutifyouwantyourJSONkeynamestostartwithalowercaseletteryoushouldusestructtagsOtherwiseGowillnotproducedataforinternalfields
typeServerstruct
ServerNamestring`jsonserverName`
ServerIPstring`jsonserverIP`
typeServerslicestruct
Servers[]Server`jsonservers`
AfterthismodificationwecanproducethesameJSONdataasbefore
HerearesomepointsyouneedtokeepinmindwhentryingtoproduceJSON
Fieldtagscontaining-willnotbeoutputtedIfatagcontainsacustomizednameGousesthisinsteadofthefieldnamelikeserverNameintheaboveexampleIfatagcontainsomitemptythisfieldwillnotbeoutputtedifitiszero-valueIfthefieldtypeisboolstringintint64etcanditstagcontainsstringGoconvertsthisfieldtoitscorrespondingJSONtype
Example
JSON
160
typeServerstruct
IDwillnotbeoutputed
IDint`json-`
ServerName2willbeconvertedtoJSONtype
ServerNamestring`jsonserverName`
ServerName2string`jsonserverName2string`
IfServerIPisemptyitwillnotbeoutputted
ServerIPstring`jsonserverIPomitempty`
s=Server
ID3
ServerName`Go10`
ServerName2`Go10`
ServerIP``
b_=jsonMarshal(s)
osStdoutWrite(b)
Output
serverNameGo10serverName2Go10
TheMarshalfunctiononlyreturnsdatawhenithassucceededsoherearesomepointsweneedtokeepinmind
JSONonlysupportsstringsaskeyssoifyouwanttoencodeamapitstypehastobemap[string]TwhereTisthetypeinGoTypeslikechannelcomplextypesandfunctionsarenotcapableofbeingencodedtoJSONDonottrytoencodecyclicdataitleadstoaninfiniterecursionIfthefieldisapointerGooutputsthedatathatitpointstoorelseoutputsnullifitpointstonil
InthissectionweintroducedhowtodecodeandencodeJSONdatainGoWealsolookedatonethird-partyprojectcalledsimplejsonwhichisusefulforparsingJSONorunknownformatTheseareallusefulconceptsfordevelopingwebapplicationsinGo
LinksDirectoryPrevioussectionXMLNextsectionRegexp
JSON
161
73RegexpRegularExpressions(Regexp)isacomplicatedbutpowerfultoolforpatternmatchingandtextmanipulationAlthoughitdoesnotperformaswellaspuretextmatchingitsmoreflexibleBasedonitssyntaxyoucanfilteralmostanykindoftextfromyoursourcecontentIfyouneedtocollectdatainwebdevelopmentitsnotdifficulttouseRegexptoretrievemeaningfuldata
GohastheregexppackagewhichprovidesofficialsupportforregexpIfyouvealreadyusedregexpinotherprogramminglanguagesyoushouldbefamiliarwithitNotethatGoimplementedRE2standardexceptforCFormoredetailsfollowthislinkhttpcodegooglecompre2wikiSyntax
Gosstringspackagecanactuallydomanyjobslikesearching(ContainsIndex)replacing(Replace)parsing(SplitJoin)etcanditsfasterthanRegexpHoweverthesearealltrivialoperationsIfyouwanttosearchacaseinsensitivestringRegexpshouldbeyourbestchoiceSoifthestringspackageissufficientforyourneedsjustuseitsinceitseasytouseandreadifyouneedtoperformmoreadvancedoperationsuseRegexp
IfyourecallformvalidationfromprevioussectionsweusedRegexptoverifythevalidityofuserinputinformationBeawarethatallcharactersareUTF-8LetslearnmoreabouttheGoregexppackage
MatchTheregexppackagehas3functionstomatchifitmatchesapatternthenitreturnstruereturningfalseotherwise
funcMatch(patternstringb[]byte)(matchedboolerrorerror)
funcMatchReader(patternstringrioRuneReader)(matchedboolerrorerror)
funcMatchString(patternstringsstring)(matchedboolerrorerror)
All3functionscheckifpatternmatchestheinputsourcereturningtrueifitmatchesHoweverifyourRegexhassyntaxerrorsitwillreturnanerrorThe3inputsourcesofthesefunctionsaresliceofbyteRuneReaderandstring
HereisanexampleofhowtoverifyanIPaddress
funcIsIP(ipstring)(bbool)
ifm_=regexpMatchString(^[0-9]13[0-9]13[0-9]13[0-9]13$ip)m
returnfalse
returntrue
AsyoucanseeusingpatternintheregexppackageisnotthatdifferentHeresonemoreexampleonverifyingwhetheruserinputisvalid
funcmain()
iflen(osArgs)==1
fmtPrintln(Usageregexp[string])
osExit(1)
elseifm_=regexpMatchString(^[0-9]+$osArgs[1])m
fmtPrintln(Number)
else
fmtPrintln(Notnumber)
IntheaboveexamplesweuseMatch(Reader|String)tocheckifcontentisvalidbuttheyarealleasytouse
Regexp
162
FilterMatchmodecanverifycontentbutitcannotcutfilterorcollectdatafromitIfyouwanttodothatyouhavetousethecomplexmodeofRegexp
LetssayweneedtowriteacrawlerHereisanexampleforwhenyoumustuseRegexptofilterandcutdata
packagemain
import(
fmt
ioioutil
nethttp
regexp
strings
)
funcmain()
resperr=httpGet(httpwwwbaiducom)
iferr=nil
fmtPrintln(httpgeterror)
deferrespBodyClose()
bodyerr=ioutilReadAll(respBody)
iferr=nil
fmtPrintln(httpreaderror)
return
src=string(body)
ConvertHTMLtagstolowercase
re_=regexpCompile(lt[Ss]+gt)
src=reReplaceAllStringFunc(srcstringsToLower)
RemoveSTYLE
re_=regexpCompile(ltstyle[Ss]+ltstylegt)
src=reReplaceAllString(src)
RemoveSCRIPT
re_=regexpCompile(ltscript[Ss]+ltscriptgt)
src=reReplaceAllString(src)
RemoveallHTMLcodeinanglebracketsandreplacewithnewline
re_=regexpCompile(lt[Ss]+gt)
src=reReplaceAllString(srcn)
Removecontinuousnewline
re_=regexpCompile(s2)
src=reReplaceAllString(srcn)
fmtPrintln(stringsTrimSpace(src))
InthisexampleweuseCompileasthefirststepforcomplexmodeItverifiesthatyourRegexsyntaxiscorrectthenreturnsaRegexpforparsingcontentinotheroperations
HerearesomefunctionstoparseyourRegexpsyntax
funcCompile(exprstring)(Regexperror)
funcCompilePOSIX(exprstring)(Regexperror)
funcMustCompile(strstring)Regexp
funcMustCompilePOSIX(strstring)Regexp
Regexp
163
ThedifferencebetweenComplePOSIXandCompileisthattheformerhastousePOSIXsyntaxwhichisleftmostlongestsearchandthelatterisonlyleftmostsearchForinstanceforRegexp[a-z]24andcontentaa09aaa88aaaaCompilePOSIXreturnsaaaabutCompilereturnsaaMustprefixmeanspanicwhentheRegexpsyntaxisnotcorrectreturningerrorotherwise
NowthatweknowhowtocreateanewRegexpletsseehowthemethodsprovidedbythisstructcanhelpustooperateoncontent
func(reRegexp)Find(b[]byte)[]byte
func(reRegexp)FindAll(b[]bytenint)[][]byte
func(reRegexp)FindAllIndex(b[]bytenint)[][]int
func(reRegexp)FindAllString(sstringnint)[]string
func(reRegexp)FindAllStringIndex(sstringnint)[][]int
func(reRegexp)FindAllStringSubmatch(sstringnint)[][]string
func(reRegexp)FindAllStringSubmatchIndex(sstringnint)[][]int
func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte
func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int
func(reRegexp)FindIndex(b[]byte)(loc[]int)
func(reRegexp)FindReaderIndex(rioRuneReader)(loc[]int)
func(reRegexp)FindReaderSubmatchIndex(rioRuneReader)[]int
func(reRegexp)FindString(sstring)string
func(reRegexp)FindStringIndex(sstring)(loc[]int)
func(reRegexp)FindStringSubmatch(sstring)[]string
func(reRegexp)FindStringSubmatchIndex(sstring)[]int
func(reRegexp)FindSubmatch(b[]byte)[][]byte
func(reRegexp)FindSubmatchIndex(b[]byte)[]int
These18methodsincludeidenticalfunctionsfordifferentinputsources(byteslicestringandioRuneReader)sowecanreallysimplifythislistbyignoringinputsourcesasfollows
func(reRegexp)Find(b[]byte)[]byte
func(reRegexp)FindAll(b[]bytenint)[][]byte
func(reRegexp)FindAllIndex(b[]bytenint)[][]int
func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte
func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int
func(reRegexp)FindIndex(b[]byte)(loc[]int)
func(reRegexp)FindSubmatch(b[]byte)[][]byte
func(reRegexp)FindSubmatchIndex(b[]byte)[]int
Codesample
Regexp
164
packagemain
import(
fmt
regexp
)
funcmain()
a=IamlearningGolanguage
re_=regexpCompile([a-z]24)
Findthefirstmatch
one=reFind([]byte(a))
fmtPrintln(Findstring(one))
Findallmatchesandsavetoaslicenlessthan0meansreturnallmatchesindicateslengthofsliceifit
sgreaterthan0
all=reFindAll([]byte(a)-1)
fmtPrintln(FindAllall)
Findindexoffirstmatchstartandendposition
index=reFindIndex([]byte(a))
fmtPrintln(FindIndexindex)
Findindexofallmatchesthendoessamejobasabove
allindex=reFindAllIndex([]byte(a)-1)
fmtPrintln(FindAllIndexallindex)
re2_=regexpCompile(am()lang())
Findfirstsubmatchandreturnarraythefirstelementcontainsallelementsthesecondelementcontainsthe
resultoffirst()thethirdelementcontainstheresultofsecond()
Output
thefirstelementamlearningGolanguage
thesecondelementlearningGonoticespaceswillbeoutputedaswell
thethirdelementuage
submatch=re2FindSubmatch([]byte(a))
fmtPrintln(FindSubmatchsubmatch)
for_v=rangesubmatch
fmtPrintln(string(v))
SameasFindIndex()
submatchindex=re2FindSubmatchIndex([]byte(a))
fmtPrintln(submatchindex)
FindAllSubmatchfindallsubmatches
submatchall=re2FindAllSubmatch([]byte(a)-1)
fmtPrintln(submatchall)
FindAllSubmatchIndexfindindexofallsubmatches
submatchallindex=re2FindAllSubmatchIndex([]byte(a)-1)
fmtPrintln(submatchallindex)
AswevepreviouslymentionedRegexpalsohas3methodsformatchingTheydotheexactsamethingastheexportedfunctionsInfactthoseexportedfunctionsactuallycallthesemethodsunderthehood
func(reRegexp)Match(b[]byte)bool
func(reRegexp)MatchReader(rioRuneReader)bool
func(reRegexp)MatchString(sstring)bool
NextletsseehowtoreplacestringsusingRegexp
Regexp
165
func(reRegexp)ReplaceAll(srcrepl[]byte)[]byte
func(reRegexp)ReplaceAllFunc(src[]bytereplfunc([]byte)[]byte)[]byte
func(reRegexp)ReplaceAllLiteral(srcrepl[]byte)[]byte
func(reRegexp)ReplaceAllLiteralString(srcreplstring)string
func(reRegexp)ReplaceAllString(srcreplstring)string
func(reRegexp)ReplaceAllStringFunc(srcstringreplfunc(string)string)string
Theseareusedinthecrawlingexamplesowewillnotexplainanyfurtherhere
LetstakealookatthedefinitionofExpand
func(reRegexp)Expand(dst[]bytetemplate[]bytesrc[]bytematch[]int)[]byte
func(reRegexp)ExpandString(dst[]bytetemplatestringsrcstringmatch[]int)[]byte
SohowdoweuseExpand
funcmain()
src=[]byte(`
callhelloalice
hellobob
callhelloeve
`)
pat=regexpMustCompile(`(m)(call)s+(Pltcmdgtw+)s+(Pltarggt+)s$`)
res=[]byte
for_s=rangepatFindAllSubmatchIndex(src-1)
res=patExpand(res[]byte($cmd($arg)n)srcs)
fmtPrintln(string(res))
AtthispointyouvelearntthewholeregexppackageinGoIhopethatyoucanunderstandmorebystudyingexamplesofkeymethodssothatyoucandosomethinginterestingonyourown
LinksDirectoryPrevioussectionJSONNextsectionTemplates
Regexp
166
74Templates
WhatisatemplateHopefullyyoureawareoftheMVC(ModelViewController)designmodelwheremodelsprocessdataviewsshowtheresultsandfinallycontrollershandleuserrequestsForviewsmanydynamiclanguagesgeneratedatabywritingcodeinstaticHTMLfilesForinstanceJSPisimplementedbyinsertinglt==gtPHPbyinsertingltphpgtetc
Thefollowingdemonstratesthetemplatemechanism
Figure71Templatemechanism
MostofthecontentthatwebapplicationsrespondtoclientswithisstaticandthedynamicpartsareusuallyverysmallForexampleifyouneedtodisplayalistuserswhohavevisitedapageonlytheusernamewouldbedynamicThestyleofthelistremainsthesameAsyoucanseetemplatesareusefulforreusingstaticcontent
TemplatinginGoInGowehavethetemplatepackagetohelphandletemplatesWecanusefunctionslikeParseParseFileandExecutetoloadtemplatesfromplaintextorfilesthenevaluatethedynamicpartsasshowninfigure71
Example
funchandler(whttpResponseWriterrhttpRequest)
t=templateNew(sometemplate)Createatemplate
t_=tParseFiles(tmplwelcomehtmlnil)Parsetemplatefile
user=GetUser()Getcurrentuserinfomration
tExecute(wuser)merge
AsyoucanseeitsveryeasytouseloadandrenderdataintemplatesinGojustasinotherprogramminglanguages
Forthesakeofconveniencewewillusethefollowingrulesinourexamples
UseParsetoreplaceParseFilesbecauseParsecantestcontentdirectlyfromstringssowedontneedanyextrafilesUsemainforeveryexampleanddonotusehandlerUseosStdouttoreplacehttpResponseWritersinceosStdoutalsoimplementstheioWriterinterface
InsertingdataintoatemplateWevejustshownyouhowtoparseandrendertemplatesLetstakeitonestepfurtherandrenderdatatoourtemplatesEverytemplateisanobjectinGosohowdoweinsertfieldstotemplates
Fields
InGoEveryfieldthatyouintendtoberenderedwithinatemplateshouldbeputinsideofisshorthandforthecurrentobjectwhichissimilartoitsJavaorC++counterpartIfyouwanttoaccessthefieldsofthecurrentobjectyoushoulduseFieldNameNoticethatonlyexportedfieldscanbeaccessedintemplatesHereisanexample
Templates
167
packagemain
import(
htmltemplate
os
)
typePersonstruct
UserNamestring
funcmain()
t=templateNew(fieldnameexample)
t_=tParse(helloUserName)
p=PersonUserNameAstaxie
tExecute(osStdoutp)
TheaboveexampleoutputshelloAstaxiecorrectlybutifwemodifyourstructalittlebitthefollowingerroremerges
typePersonstruct
UserNamestring
emailstringFieldisnotexported
t_=tParse(helloUserNameemail)
ThispartofthecodewillnotbecompiledbecausewetrytoaccessafieldthathasnotbeenexportedHoweverifwetrytouseafieldthatdoesnotexistGosimplyoutputsanemptystringinsteadofanerror
IfyouprintinatemplateGooutputsaformattedstringofthisobjectcallingfmtunderthecovers
Nestedfields
WeknowhowtooutputafieldnowWhatifthefieldisanobjectanditalsohasitsownfieldsHowdoweprintthemallinoneloopWecanusewithhelliphellipendandrangehellipendforexactlythatpurpose
rangejustlikerangeinGowithletsyouwritethesameobjectnameonceanduseasshorthandforit(SimilartowithinVB)
Moreexamples
Templates
168
packagemain
import(
htmltemplate
os
)
typeFriendstruct
Fnamestring
typePersonstruct
UserNamestring
Emails[]string
Friends[]Friend
funcmain()
f1=FriendFnameminuxma
f2=FriendFnamexushiwei
t=templateNew(fieldnameexample)
t_=tParse(`helloUserName
rangeEmails
anemail
end
withFriends
range
myfriendnameisFname
end
end
`)
p=PersonUserNameAstaxie
Emails[]stringastaxiebeegomeastaxiegmailcom
Friends[]Friendampf1ampf2
tExecute(osStdoutp)
ConditionsIfyouneedtocheckforconditionsintemplatesyoucanusetheif-elsesyntaxjustlikeyoudoinregularGoprogramsIfthepipelineisemptythedefaultvalueofifisfalseThefollowingexampleshowshowtouseif-elseintemplates
packagemain
import(
os
texttemplate
)
funcmain()
tEmpty=templateNew(templatetest)
tEmpty=templateMust(tEmptyParse(Emptypipelineifdemoif``willnotbeoutputtedendn))
tEmptyExecute(osStdoutnil)
tWithValue=templateNew(templatetest)
tWithValue=templateMust(tWithValueParse(Notemptypipelineifdemoif`anything`willbeoutputtede
ndn))
tWithValueExecute(osStdoutnil)
tIfElse=templateNew(templatetest)
tIfElse=templateMust(tIfElseParse(if-elsedemoif`anything`ifpartelseelsepartendn))
tIfElseExecute(osStdoutnil)
Asyoucanseeitseasytouseif-elseintemplates
Templates
169
AttentionYouCANNOTuseconditionalexpressionsinifforinstanceMail==astaxiegmailcomOnlybooleanvaluesareacceptable
pipelines
Unixusersshouldbefamiliarwiththepipeoperatorlikels|grepbeegoThiscommandfiltersfilesandonlyshowsthosethatcontainthewordbeegoOnethingthatIlikeaboutGotemplatesisthattheysupportpipesAnythingincanbethedataofpipelinesThee-mailweusedabovecanrenderourapplicationvulnerabletoXSSattacksHowcanweaddressthisissueusingpipes
|html
Wecanusethismethodtoescapethee-mailbodytoHTMLItsquitesimilartowritingaUnixcommandanditisconvenientforuseintemplatefunctions
TemplatevariablesSometimesweneedtouselocalvariablesintemplatesWecanusethemwiththewithrangeandifkeywordsandtheirscopeisbetweenthesekeywordsandendHeresanexampleofdeclaringaglobalvariable
$variable=pipeline
Moreexamples
with$x=output|printfq$xend
with$x=outputprintfq$xend
with$x=output$x|printfqend
Templatefunctions
GousesthefmtpackagetoformatoutputintemplatesbutsometimesweneedtodosomethingelseForexampleconsiderthefollowingscenarioletssaywewanttoreplacewithatinoure-mailaddresslikeastaxieatbeegomeAtthispointwehavetowriteacustomizedfunction
EverytemplatefunctionhasauniquenameandisassociatedwithonefunctioninyourGoprogramasfollows
typeFuncMapmap[string]interface
SupposewehaveanemailDealtemplatefunctionassociatedwithitsEmailDealWithcounterpartfunctioninourGoprogramWecanusethefollowingcodetoregisterthisfunction
t=tFuncs(templateFuncMapemailDealEmailDealWith)
EmailDealWithdefinition
funcEmailDealWith(argshellipinterface)string
Example
Templates
170
packagemain
import(
fmt
htmltemplate
os
strings
)
typeFriendstruct
Fnamestring
typePersonstruct
UserNamestring
Emails[]string
Friends[]Friend
funcEmailDealWith(argsinterface)string
ok=false
varsstring
iflen(args)==1
sok=args[0](string)
ifok
s=fmtSprint(args)
findthesymbol
substrs=stringsSplit(s)
iflen(substrs)=2
returns
replacethebyat
return(substrs[0]+at+substrs[1])
funcmain()
f1=FriendFnameminuxma
f2=FriendFnamexushiwei
t=templateNew(fieldnameexample)
t=tFuncs(templateFuncMapemailDealEmailDealWith)
t_=tParse(`helloUserName
rangeEmails
anemails|emailDeal
end
withFriends
range
myfriendnameisFname
end
end
`)
p=PersonUserNameAstaxie
Emails[]stringastaxiebeegomeastaxiegmailcom
Friends[]Friendampf1ampf2
tExecute(osStdoutp)
Hereisalistofbuilt-intemplatefunctions
Templates
171
varbuiltins=FuncMap
andand
callcall
htmlHTMLEscaper
indexindex
jsJSEscaper
lenlength
notnot
oror
printfmtSprint
printffmtSprintf
printlnfmtSprintln
urlqueryURLQueryEscaper
MustThetemplatepackagehasafunctioncalledMustwhichisforvalidatingtemplateslikethematchingofbracescommentsandvariablesLetstakealookatanexampleofMust
packagemain
import(
fmt
texttemplate
)
funcmain()
tOk=templateNew(first)
templateMust(tOkParse(somestatictextandacomment))
fmtPrintln(ThefirstoneparsedOK)
templateMust(templateNew(second)Parse(somestatictextName))
fmtPrintln(ThesecondoneparsedOK)
fmtPrintln(Thenextoneoughttofail)
tErr=templateNew(checkparseerrorwithMust)
templateMust(tErrParse(somestatictextName))
Output
ThefirstoneparsedOK
ThesecondoneparsedOK
Thenextoneoughttofail
panictemplatecheckparseerrorwithMust1unexpectedincommand
NestedtemplatesJustlikeinmostwebapplicationscertainpartsoftemplatescanbereusedacrossothertemplatesliketheheadersandfootersofablogWecandeclareheadercontentandfooterassub-templatesanddeclaretheminGousingthefollowingsyntax
definesub-templatecontentend
Thesub-templateiscalledusingthefollowingsyntax
templatesub-template
Templates
172
Heresacompleteexamplesupposingthatwehavethefollowingthreefilesheadertmplcontenttmplandfootertmplinthefoldertemplateswewillreadthefolderandstorethefilenamesinastringarraywhichwewillthenusetoparsefiles
Maintemplate
raw
headertmpl
defineheader
lthtmlgt
ltheadgt
lttitlegtSomethingherelttitlegt
ltheadgt
ltbodygt
end
contenttmpl
definecontent
templateheader
lth1gtNestedherelth1gt
ltulgt
ltligtNestedusagltligt
ltligtCalltemplateltligt
ltulgt
templatefooter
end
footertmpl
definefooter
ltbodygt
lthtmlgt
end
Whenusingsubtemplatingmakesurethatyouhaveparsedeachsubtemplatefile
otherwisethecompilerwouldntunderstandwhattosubstitutewhenitreadsthetemplateheader
endraw
Code
Templates
173
packagemain
import(
fmt
os
ioioutil
texttemplate
)
vartemplatestemplateTemplate
funcmain()
varallFiles[]string
fileserr=ioutilReadDir(templates)
iferr=nil
fmtPrintln(err)
for_file=rangefiles
filename=fileName()
ifstringsHasSuffix(filenametmpl)
allFiles=append(allFilestemplates+filename)
templateserr=templateParseFiles(allFiles)parsesalltmplfilesinthetemplatesfolder
s1=templatesLookup(headertmpl)
s1ExecuteTemplate(osStdoutheadernil)
fmtPrintln()
s2=templatesLookup(contenttmpl)
s2ExecuteTemplate(osStdoutcontentnil)
fmtPrintln()
s3=templatesLookup(footertmpl)
s3ExecuteTemplate(osStdoutfooternil)
fmtPrintln()
s3Execute(osStdoutnil)
HerewecanseethattemplateParseFilesparsesallnestedtemplatesintocacheandthateverytemplatedefinedbydefineareindependentofeachotherTheyarepersistedinsomethinglikeamapwherethetemplatenamesarekeysandthevaluesarethetemplatebodiesWecanthenuseExecuteTemplatetoexecutethecorrespondingsub-templatessothattheheaderandfooterareindependentandcontentcontainsthembothNotethatifwetrytoexecutes1Executenothingwillbeoutputtedbecausethereisnodefaultsub-templateavailable
Whenyoudontwanttousedefinethenyoucanjustcreateatextfilewiththenameofthesubtemplateforinstance_headtmplisasubtemplatewhichyoulluseacrossyourprojectthencreatethisfileinthetemplatesfolderandusethenormalsyntaxLookupcacheisbasicallycreatedsothatyoudontreadthefileeverytimeyouservearequestbecauseifyoudothenyouarewastingalotofresourcesforreadingafilewhichwontchangeunlessthecodebaseisbeingrewrittenitdoesntmakesensetoparsethetemplatefilesduringeachHTTPGETrequestsothetechniqueisusedwhereweparsethefilesonceandthendoaLookup()onthecachetoexecutethetemplatewhenweneedittodisplaydata
Templatesinonesetknoweachotherbutyoumustparsethemforeverysingleset
Sometimesyouwanttocontextualizetemplatesforinstanceyouhavea_headhtmlyoumighthaveaheaderwhosvalueyouhavetopopulatebasedonwhichdatayouareloadingforinstanceforatodolistmanageryoucanhavethreecategoriespendingcompleteddeletedforthissupposeyouhaveanifstatementlikethis
lttitlegtifeqNavigationpendingTasks
elseifeqNavigationcompletedCompleted
elseifeqNavigationdeletedDeleted
elseifeqNavigationeditEdit
end
lttitlegt
Templates
174
NoteGotemplatesfollowthePolishnotationwhileperformingthecomparisonwhereyougivetheoperatorfirstandthecomparisonvalueandthevaluetobecomparedwithTheelseifpartisprettystraightforward
Typicallyweusearangeoperatortoloopthroughthecontextvariablewhichwepasstothetemplatewhileexecutionlikethis
presentinviewspackage
context=dbGetTasks(pending)truewhenyouwantnondeletednotes
homeTemplateExecute(wcontext)
Wegetthecontextobjectfromthedatabaseasastructobjectthedefinitionisasbelow
Taskisthestructusedtoidentifytasks
typeTaskstruct
Idint
Titlestring
Contentstring
Createdstring
Contextisthestructpassedtotemplates
typeContextstruct
Tasks[]Task
Navigationstring
Searchstring
Messagestring
presentindatabasepackage
vartask[]typesTask
varcontexttypesContext
context=typesContextTaskstaskNavigationstatus
Thislineisinthedatabasepackagewherethecontextisreturnedbacktotheview
WeusethetaskarrayandtheNavigationinourtemplateswesawhowweusetheNavigationinthetemplatewellseehowwellusetheactualtaskarrayinourtemplate
HereintheifTaskswefirstcheckiftheTasksfieldofourcontextobjectwhichwepassedtothetemplatewhileexecutingisemptyornotIfitisnotemptythenwewillrangethroughthatarraytopopulatethetitleandcontentofTaskThebelowexampleisveryimportantwhenitcomestoloopingthroughanarrayinatemplatewestartwiththeRangeoperatorthenwecangiveanymemberofthatstructasNamemyTaskstructurehasaTitleandaContent(pleasenotethecapitalTandCtheyareexportednamesandtheyneedtobecapitalisedunlessyouwanttomakethemprivate)
rangeTasks
Title
Content
end
ThisblockofcodewillprinteachtitleandcontentoftheTaskarrayBelowisafullexamplefromgithubcomthewhitetulipTaskshomehtmltemplate
Templates
175
ltdivclass=timelinegt
ifTasksrangeTasks
ltdivclass=notegt
ltpclass=noteHeadinggtTitleltpgt
lthrgt
ltpclass=noteContentgtContentltpgt
ltulgt
ltspangt
ltdivgt
endelse
ltdivclass=notegt
ltpclass=noteHeadinggtNoTaskshereltpgt
ltpclass=notefootergt
Createnewtaskltbuttonclass=floating-action-icon-addgthereltbuttongtltpgt
ltdivgt
end
SummaryInthissectionyoulearnedhowtocombinedynamicdatawithtemplatesusingtechniquesincludingprintingdatainloopstemplatefunctionsandnestedtemplatesBylearningabouttemplateswecanconcludediscussingtheV(View)partoftheMVCarchitectureInthefollowingchapterswewillcovertheM(Model)andC(Controller)aspectsofMVC
LinksDirectoryPrevioussectionRegexpNextsectionFiles
Templates
176
75FilesFilesareessentialobjectsoneverysinglecomputerdeviceItwontcomeasanysurprisetoyouthatwebapplicationsalsomakeheavyuseofthemInthissectionweregoingtolearnhowtooperateonfilesinGo
DirectoriesInGomostofthefileoperationfunctionsarelocatedintheospackageHerearesomedirectoryfunctions
funcMkdir(namestringpermFileMode)error
Createadirectorywithnamepermisthedirectorypermissionsie0777
funcMkdirAll(pathstringpermFileMode)error
Createmultipledirectoriesaccordingtopathlikeastaxietest1test2
funcRemove(namestring)error
RemovesdirectorywithnameReturnserrorifitsnotadirectoryornotempty
funcRemoveAll(pathstring)error
RemovesmultipledirectoriesaccordingtopathDirectorieswillnotbedeletedifpathisasinglepath
Codesample
packagemain
import(
fmt
os
)
funcmain()
osMkdir(astaxie0777)
osMkdirAll(astaxietest1test20777)
err=osRemove(astaxie)
iferr=nil
fmtPrintln(err)
osRemoveAll(astaxie)
Files
Createandopenfiles
Therearetwofunctionsforcreatingfiles
funcCreate(namestring)(fileFileerrError)
Createafilewithnameandreturnaread-writablefileobjectwithpermission0666
funcNewFile(fduintptrnamestring)File
Createafileandreturnafileobject
Therearealsotwofunctionstoopenfiles
funcOpen(namestring)(fileFileerrError)
Files
177
Opensafilecallednamewithread-onlyaccesscallingOpenFileunderthecovers
funcOpenFile(namestringflagintpermuint32)(fileFileerrError)
Opensafilecallednameflagisopenmodelikeread-onlyread-writeetcpermarethefilepermissions
WritefilesFunctionsforwritingfiles
func(fileFile)Write(b[]byte)(ninterrError)
Writebytetypecontenttoafile
func(fileFile)WriteAt(b[]byteoffint64)(ninterrError)
Writebytetypecontenttoaspecificpositionofafile
func(fileFile)WriteString(sstring)(retinterrError)
Writeastringtoafile
Codesample
packagemain
import(
fmt
os
)
funcmain()
userFile=astaxietxt
fouterr=osCreate(userFile)
iferr=nil
fmtPrintln(userFileerr)
return
deferfoutClose()
fori=0ilt10i++
foutWriteString(Justatestrn)
foutWrite([]byte(Justatestrn))
ReadfilesFunctionsforreadingfiles
func(fileFile)Read(b[]byte)(ninterrError)
Readdatatob
func(fileFile)ReadAt(b[]byteoffint64)(ninterrError)
Readdatafrompositionofftob
Codesample
Files
178
packagemain
import(
fmt
os
)
funcmain()
userFile=asatxietxt
flerr=osOpen(userFile)
iferr=nil
fmtPrintln(userFileerr)
return
deferflClose()
buf=make([]byte1024)
for
n_=flRead(buf)
if0==n
break
osStdoutWrite(buf[n])
DeletefilesGousesthesamefunctionforremovingfilesanddirectories
funcRemove(namestring)Error
Removeafileordirectorycalledname(anameendingwithsignifiesthatitsadirectory)
LinksDirectoryPrevioussectionTemplatesNextsectionStrings
Files
179
76StringsOnthewebalmosteverythingwesee(includinguserinputsdatabaseaccessetc)isrepresentedbystringsTheyareaveryimportantpartofwebdevelopmentInmanycaseswealsoneedtosplitjoinconvertandotherwisemanipulatestringsInthissectionwearegoingtointroducethestringsandstrconvpackagesfromtheGostandardlibrary
stringsThefollowingfunctionsarefromthestringspackageSeetheofficialdocumentationformoredetails
funcContains(ssubstrstring)bool
Checkifstringscontainsstringsubstrreturnsabooleanvalue```GofmtPrintln(stringsContains(seafoodfoo))fmtPrintln(stringsContains(seafoodbar))fmtPrintln(stringsContains(seafood))fmtPrintln(stringsContains())
Outputtruefalsetruetrue
-funcJoin(a[]stringsepstring)string
Combinestringsfromslicewithseparator`sep`
```Go
s=[]stringfoobarbaz
fmtPrintln(stringsJoin(s))
Outputfoobarbaz
funcIndex(ssepstring)int
Findindexofsepinstringsreturns-1ifitsnotfound
fmtPrintln(stringsIndex(chickenken))
fmtPrintln(stringsIndex(chickendmr))
Output4
-1
funcRepeat(sstringcountint)string
Repeatstringscounttimes
fmtPrintln(ba+stringsRepeat(na2))
Outputbanana
funcReplace(soldnewstringnint)string
ReplacestringoldwithstringnewinstringsnisthenumberofreplacementsIfnislessthan0replaceallinstances
fmtPrintln(stringsReplace(oinkoinkoinkkky2))
fmtPrintln(stringsReplace(oinkoinkoinkoinkmoo-1))
Outputoinkyoinkyoink
moomoomoo
funcSplit(ssepstring)[]string
Splitstringswithseparatorsepintoaslice
Strings
180
fmtPrintf(qnstringsSplit(abc))
fmtPrintf(qnstringsSplit(amanaplanacanalpanamaa))
fmtPrintf(qnstringsSplit(xyz))
fmtPrintf(qnstringsSplit(BernardoOHiggins))
Output[abc]
[manplancanalpanama]
[xyz]
[]
funcTrim(sstringcutsetstring)string
Removecutsetofstringsifitsleftmostorrightmost
fmtPrintf([q]stringsTrim(Achtung))
Output[Achtung]
funcFields(sstring)[]string
Removespaceitemsandsplitstringwithspaceintoaslice
fmtPrintf(FieldsareqstringsFields(foobarbaz))
OutputFieldsare[foobarbaz]
strconvThefollowingfunctionsarefromthestrconvpackageAsusualpleaseseeofficialdocumentationformoredetails
Appendseriesconvertdatatostringandappendtocurrentbyteslice```Gopackagemain
import(fmtstrconv)
funcmain()str=make([]byte0100)str=strconvAppendInt(str456710)str=strconvAppendBool(strfalse)str=strconvAppendQuote(strabcdefg)str=strconvAppendQuoteRune(str单)fmtPrintln(string(str))
-Formatseriesconvertotherdatatypesintostring
```Go
packagemain
import(
fmt
strconv
)
funcmain()
a=strconvFormatBool(false)
b=strconvFormatFloat(12323g1264)
c=strconvFormatInt(123410)
d=strconvFormatUint(1234510)
e=strconvItoa(1023)
fmtPrintln(abcde)
Parseseriesconvertstringstoothertypes```Gopackagemain
import(fmtstrconv)
funcmain()aerr=strconvParseBool(false)iferr=nilfmtPrintln(err)berr=strconvParseFloat(1232364)iferr=nilfmtPrintln(err)cerr=strconvParseInt(12341064)iferr=nilfmtPrintln(err)derr=strconvParseUint(123451064)iferr=nilfmtPrintln(err)eerr=strconvItoa(1023)iferr=nilfmtPrintln(err)fmtPrintln(abcde)```
Strings
181
LinksDirectoryPrevioussectionFilesNextsectionSummary
Strings
182
77SummaryInthischapterweintroducedsometextprocessingtoolslikeXMLJSONRegexpandwealsotalkedabouttemplatesXMLandJSONaredataexchangetoolsYoucanrepresentalmostanykindofinformationusingthesetwoformatsRegexpisapowerfultoolforsearchingreplacingandcuttingtextcontentWithtemplatesyoucaneasilycombinedynamicdatawithstaticfilesThesetoolsareallusefulwhendevelopingwebapplicationsIhopethatyounowhaveabetterunderstandingofprocessinganddisplayingcontentusingGo
LinksDirectoryPrevioussectionStringsNextchapterWebservices
Summary
183
8WebservicesWebservicesallowyouuseformatslikeXMLorJSONtoexchangeinformationthroughHTTPForexampleifyouwanttoknowtheweatherinShanghaitomorrowthecurrentsharepriceofAppleorproductinformationonAmazonyoucanwriteapieceofcodetofetchthatinformationfromopenplatformsInGothisprocesscanbecomparabletocallingalocalfunctionandgettingitsreturnvalue
ThekeypointisthatwebservicesareplatformindependentThisallowsyoutodeployyourapplicationsonLinuxandinteractwithASPNETapplicationsinWindowsforexamplejustlikeyouwouldnthaveaprobleminteractingwithJSPonFreeBSDeither
TheRESTarchitectureandSOAPprotocolarethemostpopularstylesinwhichwebservicescanbeimplementedthesedays
RESTrequestsareprettystraightforwardbecauseitsbasedonHTTPEveryRESTrequestisactuallyanHTTPrequestandservershandlerequestsusingdifferentmethodsBecausemanydevelopersarefamiliarwithHTTPalreadyRESTshouldfeellikeitsalreadyintheirbackpocketsWearegoingtoshowyouhowtoimplementRESTinGoinsection83SOAPisastandardforcross-networkinformationtransmissionandremotecomputerfunctioncallslaunchedbyW3CTheproblemwithSOAPisthatitsspecificationisverylongandcomplicatedanditsstillgettinglongerGobelievesthatthingsshouldbesimplesowerenotgoingtotalkaboutSOAPFortunatelyGoprovidessupportforRPC(RemoteProcedureCalls)whichhasgoodperformanceandiseasytodevelopwithsowewillintroducehowtoimplementRPCinGoinsection84
GoistheClanguageofthe21stcenturyaspiringtobesimpleyetperformantWiththesequalitiesinmindwellintroduceyoutosocketprogramminginGoinsection81Nowadaysmanyreal-timeserversusesocketstoovercomethelowperformanceofHTTPAlongwiththerapiddevelopmentofHTML5websocketsarenowusedbymanywebbasedgamecompaniesandwewilltalkaboutthismoreinsection82
LinksDirectoryPreviousChapterChapter7SummaryNextsectionSockets
Webservices
184
81SocketsSomenetworkapplicationdeveloperssaythatthelowerapplicationlayersareallaboutsocketprogrammingThismaynotbetrueforallcasesbutmanymodernwebapplicationsdoindeedusesocketstotheiradvantageHaveyoueverwonderedhowbrowserscommunicatewithwebserverswhenyouaresurfingtheinternetOrHowMSNconnectsyouandyourfriendstogetherinachatroomrelayingeachmessageinreal-timeManyservicesliketheseusesocketstotransferdataAsyoucanseesocketsoccupyanimportantpositioninnetworkprogrammingtodayandweregoingtolearnaboutusingsocketsinGointhissection
WhatisasocketSocketsoriginatefromUnixandgiventhebasiceverythingisafilephilosophyofUnixeverythingcanbeoperatedonwithopen-gtwriteread-gtcloseSocketsareoneimplementationofthisphilosophySocketshaveafunctioncallforopeningasocketjustlikeyouwouldopenafileThisreturnsanintdescriptorofthesocketwhichcanthenbeusedforoperationslikecreatingconnectionstransferringdataetc
Twotypesofsocketsthatarecommonlyusedarestreamsockets(SOCK_STREAM)anddatagramsockets(SOCK_DGRAM)Streamsocketsareconnection-orientedlikeTCPwhiledatagramsocketsdonotestablishconnectionslikeUDP
SocketcommunicationBeforeweunderstandhowsocketscommunicatewithoneanotherweneedtofigureouthowtomakesurethateverysocketisuniqueotherwiseestablishingareliablecommunicationchannelisalreadyoutofthequestionWecangiveeveryprocessauniquePIDwhichservesourpurposelocallyhoweverthatsnotabletoworkoveranetworkFortunatelyTCPIPhelpsussolvethisproblemTheIPaddressesofthenetworklayerareuniqueinanetworkofhostsandprotocol+portisalsouniqueamonghostapplicationsSowecanusetheseprinciplestomakesocketswhichareunique
Figure81networkprotocollayers
ApplicationsthatarebasedonTCPIPallusesocketAPIsintheircodeinonewayoranotherGiventhatnetworkedapplicationsarebecomingmoreandmoreprevalentinthemoderndayitsnowondersomedevelopersaresayingthateverythingisaboutsockets
SocketbasicknowledgeWeknowthatsocketshavetwotypeswhichareTCPsocketsandUDPsocketsTCPandUDPareprotocolsandasmentionedwealsoneedanIPaddressandportnumbertohaveauniquesocket
IPv4TheglobalinternetusesTCPIPasitsprotocolwhereIPisthenetworklayerandacorepartofTCPIPIPv4signifiesthatitsversionis4infrastructuredevelopmenttodatehasspannedover30years
ThenumberofbitsinanIPv4addressis32whichmeansthat2^32devicesareabletouniquelyconnecttotheinternetDuetotherapiddevelopoftheinternetIPaddressesarealreadyrunningoutofstockinrecentyears
Addressformat127001172122121111
IPv6
Sockets
185
IPv6isthenextversionornextgenerationoftheinternetItsbeingdevelopedforsolvingmanyoftheproblemsinherentwithIPv4DevicesusingIPv6haveanaddressthats128bitslongsowellneverneedtoworryaboutashortageofuniqueaddressesToputthisintoperspectiveyoucouldhavemorethan1000IPaddressesforeverysquaremeteronearthwithIPv6Otherproblemslikepeertopeerconnectionservicequality(QoS)securitymultiplebroadcastetcarealsobeimproved
Addressformat2002c0e882e7000c0e882e7
IPtypesinGo
ThenetpackageinGoprovidesmanytypesfunctionsandmethodsfornetworkprogrammingThedefinitionofIPasfollows
typeIP[]byte
FunctionParseIP(sstring)IPistoconverttheIPv4orIPv6formattoanIP
packagemain
import(
net
os
fmt
)
funcmain()
iflen(osArgs)=2
fmtFprintf(osStderrUsagesip-addrnosArgs[0])
osExit(1)
name=osArgs[1]
addr=netParseIP(name)
ifaddr==nil
fmtPrintln(Invalidaddress)
else
fmtPrintln(TheaddressisaddrString())
osExit(0)
ItreturnsthecorrespondingIPformatforagivenIPaddress
TCPsocketWhatcanwedowhenweknowhowtovisitawebservicethroughanetworkportAsaclientwecansendarequesttoanappointednetworkportandgetsitsresponseasaserverweneedtobindaservicetoanappointednetworkportwaitforclientsrequestsandsupplyaresponse
InGosnetpackagetheresatypecalledTCPConnthatfacilitatesthiskindofclientsserversinteractionThistypehastwokeyfunctions
func(cTCPConn)Write(b[]byte)(ninterrosError)
func(cTCPConn)Read(b[]byte)(ninterrosError)
TCPConncanbeusedbyeitherclientorserverforreadingandwritingdata
WealsoneedaTCPAddrtorepresentTCPaddressinformation
Sockets
186
typeTCPAddrstruct
IPIP
Portint
WeusetheResolveTCPAddrfunctiontogetaTCPAddrinGo
funcResolveTCPAddr(netaddrstring)(TCPAddrosError)
Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyaddrcanbeadomainnameorIPaddresslikewwwgooglecom80or12700122
TCPclientGoclientsusetheDialTCPfunctioninthenetpackagetocreateaTCPconnectionwhichreturnsaTCPConnobjectafteraconnectionisestablishedtheserverhasthesametypeofconnectionobjectforthecurrentconnectionandclientandservercanbeginexchangingdatawithoneanotherIngeneralclientssendrequeststoserversthroughaTCPConnandreceiveinformationfromtheserverresponseserversreadandparseclientrequeststhenreturnfeedbackThisconnectionwillremainvaliduntileithertheclientorserverclosesitThefunctionforcreatingaconnectionisasfollows
funcDialTCP(netstringladdrraddrTCPAddr)(cTCPConnerrosError)
Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyladdrrepresentsthelocaladdresssetittonilinmostcasesraddrrepresentstheremoteaddress
LetswriteasimpleexampletosimulateaclientrequestingaconnectiontoaserverbasedonanHTTPrequestWeneedasimpleHTTPrequestheader
HEADHTTP10rnrn
Serverresponseinformationformatmaylooklikethefollowing
HTTP10200OK
ETag-9985996
Last-ModifiedThu25Mar2010175110GMT
Content-Length18074
Connectionclose
DateSat28Aug2010004348GMT
Serverlighttpd1423
Clientcode
Sockets
187
packagemain
import(
fmt
ioioutil
net
os
)
funcmain()
iflen(osArgs)=2
fmtFprintf(osStderrUsageshostportosArgs[0])
osExit(1)
service=osArgs[1]
tcpAddrerr=netResolveTCPAddr(tcp4service)
checkError(err)
connerr=netDialTCP(tcpniltcpAddr)
checkError(err)
_err=connWrite([]byte(HEADHTTP10rnrn))
checkError(err)
resulterr=ioutilReadAll(conn)
checkError(err)
fmtPrintln(string(result))
osExit(0)
funccheckError(errerror)
iferr=nil
fmtFprintf(osStderrFatalerrorserrError())
osExit(1)
IntheaboveexampleweuseuserinputastheserviceargumentofnetResolveTCPAddrtogetatcpAddrPassingtcpAddrtotheDialTCPfunctionwecreateaTCPconnectionconnWecanthenuseconntosendrequestinformationtotheserverFinallyweuseioutilReadAlltoreadallthecontentfromconnwhichcontainstheserverresponse
TCPserver
WehaveaTCPclientnowWecanalsousethenetpackagetowriteaTCPserverOntheserversideweneedtobindourservicetoaspecificinactiveportandlistenforanyincomingclientrequests
funcListenTCP(netstringladdrTCPAddr)(lTCPListenererrosError)
func(lTCPListener)Accept()(cConnerrosError)
TheargumentsrequiredhereareidenticaltothoserequiredbytheDialTCPfunctionweusedearlierLetsimplementatimesyncingserviceusingport7777
Sockets
188
packagemain
import(
fmt
net
os
time
)
funcmain()
service=7777
tcpAddrerr=netResolveTCPAddr(tcp4service)
checkError(err)
listenererr=netListenTCP(tcptcpAddr)
checkError(err)
for
connerr=listenerAccept()
iferr=nil
continue
daytime=timeNow()String()
connWrite([]byte(daytime))dontcareaboutreturnvalue
connClose()werefinishedwiththisclient
funccheckError(errerror)
iferr=nil
fmtFprintf(osStderrFatalerrorserrError())
osExit(1)
AftertheserviceisstarteditwaitsforclientrequestsWhenitreceivesaclientrequestitAcceptsitandreturnsaresponsetotheclientcontaininginformationaboutthecurrenttimeItsworthnotingthatwhenerrorsoccurintheforlooptheservicecontinuesrunninginsteadofexitingInsteadofcrashingtheserverwillrecordtheerrortoaservererrorlog
TheabovecodeisstillnotgoodenoughhoweverWedidntmakeuseofgoroutineswhichwouldhaveallowedustoacceptsimultaneousrequestsLetsdothisnow
Sockets
189
packagemain
import(
fmt
net
os
time
)
funcmain()
service=1200
tcpAddrerr=netResolveTCPAddr(tcp4service)
checkError(err)
listenererr=netListenTCP(tcptcpAddr)
checkError(err)
for
connerr=listenerAccept()
iferr=nil
continue
gohandleClient(conn)
funchandleClient(connnetConn)
deferconnClose()
daytime=timeNow()String()
connWrite([]byte(daytime))dontcareaboutreturnvalue
werefinishedwiththisclient
funccheckError(errerror)
iferr=nil
fmtFprintf(osStderrFatalerrorserrError())
osExit(1)
ByseparatingoutourbusinessprocessfromthehandleClientfunctionandbyusingthegokeywordwevealreadyimplementedconcurrencyinourserviceThisisagooddemonstrationofthepowerandsimplicityofgoroutines
SomeofyoumaybethinkingthefollowingthisserverdoesnotdoanythingmeaningfulWhatifweneededtosendmultiplerequestsfordifferenttimeformatsoverasingleconnectionHowwouldwedothat
Sockets
190
packagemain
import(
fmt
net
os
time
strconv
)
funcmain()
service=1200
tcpAddrerr=netResolveTCPAddr(tcp4service)
checkError(err)
listenererr=netListenTCP(tcptcpAddr)
checkError(err)
for
connerr=listenerAccept()
iferr=nil
continue
gohandleClient(conn)
funchandleClient(connnetConn)
connSetReadDeadline(timeNow()Add(2timeMinute))set2minutestimeout
request=make([]byte128)setmaximumrequestlengthto128Btopreventfloodbasedattacks
deferconnClose()closeconnectionbeforeexit
for
read_lenerr=connRead(request)
iferr=nil
fmtPrintln(err)
break
ifread_len==0
breakconnectionalreadyclosedbyclient
elseifstring(request[read_len])==timestamp
daytime=strconvFormatInt(timeNow()Unix()10)
connWrite([]byte(daytime))
else
daytime=timeNow()String()
connWrite([]byte(daytime))
funccheckError(errerror)
iferr=nil
fmtFprintf(osStderrFatalerrorserrError())
osExit(1)
InthisexampleweuseconnRead()toconstantlyreadclientrequestsWecannotclosetheconnectionbecauseclientsmayissuemorethanonerequestDuetothetimeoutwesetusingconnSetReadDeadline()theconnectionclosesautomaticallyafterourallottedtimeperiodWhentheexpirytimehaselapsedourprogrambreaksfromtheforloopNoticethatrequestneedstobecreatedwithamaxsizelimitationinordertopreventfloodattacks
ControllingTCPconnections
ControllingTCPfunctions
funcDialTimeout(netaddrstringtimeouttimeDuration)(Connerror)
Sockets
191
SettingthetimeoutofconnectionsThesearesuitableforuseonbothclientsandservers
func(cTCPConn)SetReadDeadline(ttimeTime)error
func(cTCPConn)SetWriteDeadline(ttimeTime)error
Settingthewritereadtimeoutofoneconnection
func(cTCPConn)SetKeepAlive(keepalivebool)osError
ItsworthtakingsometimetothinkabouthowlongyouwantyourconnectiontimeoutstobeLongconnectionscanreducetheamountofoverheadinvolvedincreatingconnectionsandaregoodforapplicationsthatneedtoexchangedatafrequently
FormoredetailedinformationjustlookuptheofficialdocumentationforGosnetpackage
UDPsocketsTheonlydifferencebetweenaUDPsocketandaTCPsocketistheprocessingmethodfordealingwithmultiplerequestsonserversideThisarisesfromthefactthatUDPdoesnothaveafunctionlikeAcceptAlloftheotherfunctionshaveUDPcounterpartsjustreplaceTCPwithUDPinthefunctionsmentionedabove
funcResolveUDPAddr(netaddrstring)(UDPAddrosError)
funcDialUDP(netstringladdrraddrUDPAddr)(cUDPConnerrosError)
funcListenUDP(netstringladdrUDPAddr)(cUDPConnerrosError)
func(cUDPConn)ReadFromUDP(b[]byte)(nintaddrUDPAddrerrosError
func(cUDPConn)WriteToUDP(b[]byteaddrUDPAddr)(ninterrosError)
UDPclientcodesample
packagemain
import(
fmt
net
os
)
funcmain()
iflen(osArgs)=2
fmtFprintf(osStderrUsageshostportosArgs[0])
osExit(1)
service=osArgs[1]
udpAddrerr=netResolveUDPAddr(udp4service)
checkError(err)
connerr=netDialUDP(udpniludpAddr)
checkError(err)
_err=connWrite([]byte(anything))
checkError(err)
varbuf[512]byte
nerr=connRead(buf[0])
checkError(err)
fmtPrintln(string(buf[0n]))
osExit(0)
funccheckError(errerror)
iferr=nil
fmtFprintf(osStderrFatalerrorerrError())
osExit(1)
Sockets
192
UDPservercodesample
packagemain
import(
fmt
net
os
time
)
funcmain()
service=1200
udpAddrerr=netResolveUDPAddr(udp4service)
checkError(err)
connerr=netListenUDP(udpudpAddr)
checkError(err)
for
handleClient(conn)
funchandleClient(connnetUDPConn)
varbuf[512]byte
_addrerr=connReadFromUDP(buf[0])
iferr=nil
return
daytime=timeNow()String()
connWriteToUDP([]byte(daytime)addr)
funccheckError(errerror)
iferr=nil
fmtFprintf(osStderrFatalerrorerrError())
osExit(1)
SummaryThroughdescribingandcodingsomesimpleprogramsusingTCPandUDPsocketswecanseethatGoprovidesexcellentsupportforsocketprogrammingandthattheyarefunandeasytouseGoalsoprovidesmanyfunctionsforbuildinghighperformancesocketapplications
LinksDirectoryPrevioussectionWebservicesNextsectionWebSocket
Sockets
193
82WebSocketsWebSocketsareanimportantfeatureofHTML5Itimplementsbrowserbasedremotesocketswhichallowsbrowserstohavefull-duplexcommunicationswithserversMainstreambrowserslikeFirefoxGoogleChromeandSafariprovidesupportforthisWebSockets
PeopleoftenusedrollpollingforinstantmessagingservicesbeforeWebSocketswerebornwhichallowclientstosendHTTPrequestsperiodicallyTheserverthenreturnsthelatestdatatoclientsThedownsidetothismethodisthatitrequiresclientstokeepsendingmanyrequeststotheserverwhichcanconsumealargeamountofbandwidth
WebSocketsuseaspecialkindofheaderthatreducesthenumberofhandshakesrequiredbetweenbrowserandservertoonlyoneforestablishingaconnectionThisconnectionwillremainactivethroughoutitslifetimeandyoucanuseJavaScripttowriteorreaddatafromthisconnectionasinthecaseofaconventionalTCPsocketsItsolvesmanyoftheheadacheinvolvedwithreal-timewebdevelopmentandhasthefollowingadvantagesovertraditionalHTTP
OnlyoneTCPconnectionforasinglewebclientWebSocketserverscanpushdatatowebclientsLightweightheadertoreducedatatransmissionoverhead
WebSocketURLsbeginwithwsorwss(SSL)ThefollowingfigureshowsthecommunicationprocessofWebSocketsAparticularHTTPheaderissenttotheserveraspartofthehandshakingprotocolandtheconnectionisestablishedThenserversorclientsareabletosendorreceivedatathroughJavaScriptviaWebSocketThissocketcanthenbeusedbyaneventhandlertoreceivedataasynchronously
Figure82WebSocketprinciple
WebSocketprinciplesTheWebSocketprotocolisactuallyquitesimpleAftersuccessfullycompletingtheinitialhandshakeaconnectionisestablishedSubsequentdatacommunicationswillallbeginwithx00andendwithxFFThisprefixandsuffixwillbevisibletoclientsbecausetheWebSocketwillbreakoffbothendyieldingtherawdataautomatically
WebSocketconnectionsarerequestedbybrowsersandrespondedtobyserversafterwhichtheconnectionisestablishedThisprocessisoftencalledhandshaking
Considerthefollowingrequestsandresponses
Figure83WebSocketrequestandresponse
Sec-WebSocket-keyisgeneratedrandomlyasyoumayhavealreadyguessedanditsbase64encodedServersneedtoappendthiskeytoafixedstringafteracceptingarequest
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Supposewehavef7cb4ezEAl6C3wRaU6JORA==thenwehave
f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Usesha1tocomputethebinaryvalueandusebase64toencodeitWewillthenwehave
rE91AJhfC+6JdVcVXOGJEADEJdQ=
WebSocket
194
UsethisasthevalueoftheSec-WebSocket-Acceptresponseheader
WebSocketinGoTheGostandardlibrarydoesnotsupportWebSocketsHoweverthewebsocketpackagewhichisasub-packageofgonetdoesandisofficiallymaintainedandsupported
Usegogettoinstallthispackage
gogetgolangorgxnetwebsocket
WebSocketshavebothclientandserversidesLetsseeasimpleexamplewhereauserinputssomeinformationontheclientsideandsendsittotheserverthroughaWebSocketfollowedbytheserverpushinginformationbacktotheclient
Clientcode
lthtmlgt
ltheadgtltheadgt
ltbodygt
ltscripttype=textjavascriptgt
varsock=null
varwsuri=ws1270011234
windowonload=function()
consolelog(onload)
sock=newWebSocket(wsuri)
sockonopen=function()
consolelog(connectedto+wsuri)
sockonclose=function(e)
consolelog(connectionclosed(+ecode+))
sockonmessage=function(e)
consolelog(messagereceived+edata)
functionsend()
varmsg=documentgetElementById(message)value
socksend(msg)
ltscriptgt
lth1gtWebSocketEchoTestlth1gt
ltformgt
ltpgt
Messageltinputid=messagetype=textvalue=Helloworldgt
ltpgt
ltformgt
ltbuttononclick=send()gtSendMessageltbuttongt
ltbodygt
lthtmlgt
AsyoucanseeitsveryeasytousetheclientsideJavaScriptfunctionstoestablishaconnectionTheonopeneventgetstriggeredaftersuccessfullycompletingtheaforementionedhandshakingprocessIttellstheclientthattheconnectionhasbeencreatedsuccessfullyClientsattemptingtoopenaconnectiontypicallybindtofourevents
1)onopentriggeredafterconnectionhasbeenestablished2)onmessagetriggeredafterreceivingamessage3)onerrortriggeredafteranerrorhasoccurred
WebSocket
195
4)onclosetriggeredaftertheconnectionhasclosed
Servercode
packagemain
import(
golangorgxnetwebsocket
fmt
log
nethttp
)
funcEcho(wswebsocketConn)
varerrerror
for
varreplystring
iferr=websocketMessageReceive(wsampreply)err=nil
fmtPrintln(Cantreceive)
break
fmtPrintln(Receivedbackfromclient+reply)
msg=Received+reply
fmtPrintln(Sendingtoclient+msg)
iferr=websocketMessageSend(wsmsg)err=nil
fmtPrintln(Cantsend)
break
funcmain()
httpHandle(websocketHandler(Echo))
iferr=httpListenAndServe(1234nil)err=nil
logFatal(ListenAndServeerr)
WhenaclientSendsuserinputinformationtheserverReceivesitandusesSendonceagaintoreturnaresponse
Figure84WebSocketserverreceivedinformation
ThroughtheexampleabovewecanseethattheclientandserversideimplementationofWebSocketsisveryconvenientWecanusethenetpackagedirectlyinGoWiththerapiddevelopmentofHTML5IthinkthatWebSocketswilltakeonamuchmoreimportantroleinmoderndaywebdevelopmentweshouldallbeatleastalittlebitfamiliarwiththem
LinksDirectoryPrevioussectionSocketsNextsectionREST
WebSocket
196
83RESTRESTisthemostpopularsoftwarearchitectureontheinternettodaybecauseitisfoundedonwelldefinedstrictstandardsanditseasytounderstandandexpandMoreandmorewebsitesarebasingtheirdesignsontopofRESTInthissectionwearegoingtohaveacloselookatimplementingtheRESTarchitectureinGoand(hopefully)learnhowtoleverageittoourbenefit
WhatisRESTThefirstdeclarationoftheconceptofREST(REpresentationalStateTransfer)wasintheyear2000inRoyThomasFieldingsdoctoraldissertationwhoalsojusthappenstobetheco-founderoftheHTTPprotocolItspecifiesthearchitecturesconstraintsandprinciplesandanythingimplementedwiththisarchitecturecanbecalledaRESTfulsystem
BeforeweunderstandwhatRESTisweneedtocoverthefollowingconcepts
Resources
RESTisthePresentationLayerStateTransferwherethepresentationlayerisactuallytheresourcepresentatio
nlayer
SowhatareresourcesPicturesdocumentsorvideosetcareallexamplesofresourcesandcanbelocatedby
URI
Representation
ResourcesarespecificinformationentitiesthatcanbeshowninavarietyofwayswithinthepresentationlayerForinstanceaTXTdocumentcanberepresentedasHTMLJSONXMLetcanimagecanberepresentedasjpgpngetc
URIsareusedtoidentifyresourcesbuthowdowedetermineitsspecificmanifestationsYouarereferredtotheAcceptandContent-TypeinanHTTPrequestheaderthesetwofieldsdescribethepresentationlayer
StateTransfer
AninteractiveprocessisinitiatedbetweenclientandservereachtimeyouvisitanypageofawebsiteDuringthisprocesscertaindatarelatedtothecurrentpagestateneedtobesavedHoweveryoullrecallthatHTTPisastatelessprotocolItsobviousthatweneedtosavethisclientstateonourserversideItfollowsthatifaclientmodifiessomedataandwantstopersistthechangestheremustbeawaytoinformtheserversideaboutthenewstate
MostofthetimeclientsinformserversofstatechangesusingHTTPTheyhavefouroperationswithwhichtodothis
-GETisusedtoobtainresources-POSTsisusedtocreateorupdateresources-PUTupdatesresources-DELETEdeletesresources
Tosummarizetheabove
(1)EveryURIrepresentsaresource(2)Thereisarepresentationlayerfortransferringresourcesbetweenclientsandservers(3)ClientsusefourHTTPmethodstoimplementPresentationLayerStateTransferallowingthemtooperateonremoteresources
ThemostimportantprincipleofwebapplicationsthatimplementRESTisthattheinteractionbetweenclientsandserversarestatelesseveryrequestshouldencapsulatealloftherequiredinformationServersshouldbeabletorestartatanytimewithouttheclientsbeingnotifiedInadditionrequestscanberespondedbyanyserverofthesameservicewhichisidealforcloudcomputingLastlybecauseitsstatelessclientscancachedataforimprovingperformance
REST
197
AnotherimportantprincipleofRESTissystemdelaminationwhichmeansthatcomponentsinonelayerhavenowayofinteractingdirectlywithcomponentsinotherlayersThiscanlimitsystemcomplexityandencourageindependenceintheunderlyingcomponents
Figure85RESTarchitecture
WhenRESTfulconstraintsarejudiciouslyabidedbywebapplicationscanbescaledtoaccommodatemassivenumbersofclientsUsingtheRESTarchitecturecanalsohelpreducedelaysbetweenclientsandserverssimplifysystemarchitectureandimprovethevisibilityofsub-systemendpoints
Figure86RESTsexpansibility
RESTfulimplementationGodoesnthavedirectsupportforRESTbutsinceRESTfulwebapplicationsareallHTTP-basedwecanusethenethttppackagetoimplementitonourownOfcoursewewillfirstneedtomakesomemodificationsbeforeweareabletofullyimplementREST
RESTusesdifferentmethodstohandleresourcesdependingontheinteractionthatsrequiredwiththatresourceManyexistingapplicationsclaimtobeRESTfulbuttheydonotactuallyimplementRESTImgoingtocategorizetheseapplicationsintoseverallevelsdependsonwhichHTTPmethodstheyimplement
Figure87RESTslevel
ThepictureaboveshowsthreelevelsthatarecurrentlyimplementedinRESTYoumaynotchoosetofollowalltherulesandconstraintsofRESTwhendevelopingyourownapplicationsbecausesometimesitsrulesarenotagoodfitforallsituationsRESTfulwebapplicationsuseeverysingleHTTPmethodincludingDELETEandPUTbutinmanycasesHTTPclientscanonlysendGETandPOSTrequests
HTMLstandardallowsclientssendGETandPOSTrequeststhroughlinksandformsItsnotpossibletosendPUTorDELETErequestswithoutAJAXsupportSomefirewallsinterceptPUTandDELETErequestsandclientshavetousePOSTinordertoimplementthemFullyRESTfulservicesareinchargeoffindingtheoriginalHTTPmethodsandrestoringthem
WecansimulatePUTandDELETErequestsbyaddingahidden_methodfieldinourPOSTrequestshowevertheserequestsmustbeconvertedontheserversidebeforetheyareprocessedMypersonalapplicationsusethisworkflowtoimplementRESTinterfacesStandardRESTfulinterfacesareeasilyimplementedinGoasthefollowingexampledemonstrates
REST
198
packagemain
import(
fmt
githubcomjulienschmidthttprouter
log
nethttp
)
funcIndex(whttpResponseWriterrhttpRequest_httprouterParams)
fmtFprint(wWelcomen)
funcHello(whttpResponseWriterrhttpRequestpshttprouterParams)
fmtFprintf(whellosnpsByName(name))
funcgetuser(whttpResponseWriterrhttpRequestpshttprouterParams)
uid=psByName(uid)
fmtFprintf(wyouaregetusersuid)
funcmodifyuser(whttpResponseWriterrhttpRequestpshttprouterParams)
uid=psByName(uid)
fmtFprintf(wyouaremodifyusersuid)
funcdeleteuser(whttpResponseWriterrhttpRequestpshttprouterParams)
uid=psByName(uid)
fmtFprintf(wyouaredeleteusersuid)
funcadduser(whttpResponseWriterrhttpRequestpshttprouterParams)
uid=rFormValue(uid)
uid=psByName(uid)
fmtFprintf(wyouareaddusersuid)
funcmain()
router=httprouterNew()
routerGET(Index)
routerGET(hellonameHello)
routerGET(useruidgetuser)
routerPOST(adduseruidadduser)
routerDELETE(deluseruiddeleteuser)
routerPUT(moduseruidmodifyuser)
logFatal(httpListenAndServe(8080router))
ThissamplecodeshowsyouhowtowriteaverybasicRESTapplicationOurresourcesareusersandweusedifferentfunctionsfordifferentmethodsHereweimportedathird-partypackagecalledgithubcomjulienschmidthttprouterWevealreadycoveredhowtoimplementacustomrouterinpreviouschapters-thejulienschmidthttprouterpackageimplementssomeveryconvenientroutermappingrulesthatmakeitveryconvenientforimplementingRESTfularchitectureAsyoucanseeRESTrequiresyoutoimplementdifferentlogicfordifferentHTTPmethodsofthesameresource
SummaryRESTisastyleofwebarchitecturebuildingonpastsuccessfulexperienceswithWWWstatelessnessresource-centricfulluseofHTTPandURIprotocolsandtheprovisionofunifiedinterfacesThesesuperiordesignconsiderationshaveallowedRESTtobecomethemostpopularwebservicesstandardInasensebyemphasizingtheURIandleveraging
REST
199
earlyInternetstandardssuchasHTTPRESThaspavedthewayforlargeandscalablewebapplicationsCurrentlythesupportthatGohasForRESTisstillverybasicHoweverbyimplementingcustomroutingrulesanddifferentrequesthandlersforeachtypeofHTTPrequestwecanachieveRESTfularchitectureinourGowebapps
LinksDirectoryPrevioussectionWebSocketNextsectionRPC
REST
200
84RPCInprevioussectionswetalkedabouthowtowritenetworkapplicationsbasedonSocketsandHTTPWelearnedthatbothofthemusetheinformationexchangemodelinwhichclientssendrequestsandserversrespondtothemThiskindofdataexchangeisbasedonaspecificformatsothatbothsidesareabletocommunicatewithoneanotherHowevermanyindependentapplicationsdonotusethismodelbutinsteadcallservicesjustliketheywouldcallnormalfunctions
RPCwasintendedtobethefunctioncallmodefornetworkedsystemsClientsexecuteRPCsliketheycallnativefunctionsexcepttheypackagethefunctionparametersandsendthemthroughthenetworktotheserverTheservercanthenunpacktheseparametersandprocesstherequestexecutingtheresultsbacktotheclient
Incomputersciencearemoteprocedurecall(RPC)isatypeofinter-processcommunicationthatallowsacomputerprogramtocauseasubroutineorproceduretoexecuteinanotheraddressspace(commonlyonanothercomputeronasharednetwork)withouttheprogrammerexplicitlycodingthedetailsforthisremoteinteractionThatistheprogrammerwritesessentiallythesamecodewhetherthesubroutineislocaltotheexecutingprogramorremoteWhenthesoftwareinquestionusesobject-orientedprinciplesRPCiscalledremoteinvocationorremotemethodinvocation
RPCworkingprinciple
Figure88RPCworkingprinciple
NormallyanRPCcallfromclienttoserverhasthefollowingtensteps
1 Calltheclienthandleexecutetransferarguments
1 Calllocalsystemkerneltosendnetworkmessages
1 Sendmessagestoremotehosts
1 Theserverreceiveshandleandarguments
1 Executeremoteprocesses
1 Returnexecutionresulttocorrespondinghandle
1 Theserverhandlecallsremotesystemkernel
1 Messagessentbacktolocalsystemkernel
1 Theclienthandlereceivesmessagesfromsystemkernel
1 Theclientgetsresultsfromcorrespondinghandle
GoRPCGohasofficialsupportforRPCinitsstandardlibraryonthreelevelswhichareTCPHTTPandJSONRPCNotethatGoRPCisnotlikeothertraditionalRPCsystemsItrequiresyoutouseGoapplicationsonbothclientandserversidesbecauseitencodescontentusingGob
RPC
201
FunctionsofGoRPCmustabidebythefollowingrulesforremoteaccessotherwisethecorrespondingcallswillbeignored
Functionsareexported(capitalized)FunctionsmusthavetwoargumentswithexportedtypesThefirstargumentisforreceivingfromtheclientandthesecondonehastobeapointerandisforreplyingtotheclientFunctionsmusthaveareturnvalueoferrortype
Forexample
func(tT)MethodName(argTypeT1replyTypeT2)error
WhereTT1andT2mustbeabletobeencodedbythepackagegobpackage
AnykindofRPChastogothroughanetworktotransferdataGoRPCcaneitheruseHTTPorTCPThebenefitsofusingHTTPisthatyoucanreusesomefunctionsfromthenethttppackage
HTTPRPCHTTPserversidecode
RPC
202
packagemain
import(
errors
fmt
nethttp
netrpc
)
typeArgsstruct
ABint
typeQuotientstruct
QuoRemint
typeArithint
func(tArith)Multiply(argsArgsreplyint)error
reply=argsAargsB
returnnil
func(tArith)Divide(argsArgsquoQuotient)error
ifargsB==0
returnerrorsNew(dividebyzero)
quoQuo=argsAargsB
quoRem=argsAargsB
returnnil
funcmain()
arith=new(Arith)
rpcRegister(arith)
rpcHandleHTTP()
err=httpListenAndServe(1234nil)
iferr=nil
fmtPrintln(errError())
WeregisteredaRPCserviceofAriththenregisteredthisserviceonHTTPthroughrpcHandleHTTPAfterthatweareabletotransferdatathroughHTTP
Clientsidecode
RPC
203
packagemain
import(
fmt
log
netrpc
os
)
typeArgsstruct
ABint
typeQuotientstruct
QuoRemint
funcmain()
iflen(osArgs)=2
fmtPrintln(UsageosArgs[0]server)
osExit(1)
serverAddress=osArgs[1]
clienterr=rpcDialHTTP(tcpserverAddress+1234)
iferr=nil
logFatal(dialingerr)
Synchronouscall
args=Args178
varreplyint
err=clientCall(ArithMultiplyargsampreply)
iferr=nil
logFatal(aritherrorerr)
fmtPrintf(Arithdd=dnargsAargsBreply)
varquotQuotient
err=clientCall(ArithDivideargsampquot)
iferr=nil
logFatal(aritherrorerr)
fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)
WecompiletheclientandtheserversidecodeseparatelythenstarttheserverandclientYoullthenhavesomethingsimilarasfollowsafteryouinputsomedata
$http_clocalhost
Arith178=136
Arith178=2remainder1
AsyoucanseewedefinedastructforthereturntypeWeuseitastypeoffunctionargumentontheserversideandasthetypeofthesecondandthirdargumentsontheclientclientCallThiscallisveryimportantIthasthreeargumentswherethefirstoneisthenameofthefunctionthatisgoingtobecalledthesecondistheargumentyouwanttopassandthelastoneisthereturnvalue(ofpointertype)SofarweseethatitseasytoimplementRPCinGo
TCPRPCLetstrytheRPCthatisbasedonTCPhereistheserversidecode
RPC
204
packagemain
import(
errors
fmt
net
netrpc
os
)
typeArgsstruct
ABint
typeQuotientstruct
QuoRemint
typeArithint
func(tArith)Multiply(argsArgsreplyint)error
reply=argsAargsB
returnnil
func(tArith)Divide(argsArgsquoQuotient)error
ifargsB==0
returnerrorsNew(dividebyzero)
quoQuo=argsAargsB
quoRem=argsAargsB
returnnil
funcmain()
arith=new(Arith)
rpcRegister(arith)
tcpAddrerr=netResolveTCPAddr(tcp1234)
checkError(err)
listenererr=netListenTCP(tcptcpAddr)
checkError(err)
for
connerr=listenerAccept()
iferr=nil
continue
rpcServeConn(conn)
funccheckError(errerror)
iferr=nil
fmtPrintln(FatalerrorerrError())
osExit(1)
ThedifferencebetweenHTTPRPCandTCPRPCisthatwehavetocontrolconnectionsbyourselvesifweuseTCPRPCthenpassconnectionstoRPCforprocessing
AsyoumayhaveguessedthisisablockingpatternYouarefreetousegoroutinestoextendthisapplicationasamoreadvancedexperiment
Theclientsidecode
RPC
205
packagemain
import(
fmt
log
netrpc
os
)
typeArgsstruct
ABint
typeQuotientstruct
QuoRemint
funcmain()
iflen(osArgs)=2
fmtPrintln(UsageosArgs[0]serverport)
osExit(1)
service=osArgs[1]
clienterr=rpcDial(tcpservice)
iferr=nil
logFatal(dialingerr)
Synchronouscall
args=Args178
varreplyint
err=clientCall(ArithMultiplyargsampreply)
iferr=nil
logFatal(aritherrorerr)
fmtPrintf(Arithdd=dnargsAargsBreply)
varquotQuotient
err=clientCall(ArithDivideargsampquot)
iferr=nil
logFatal(aritherrorerr)
fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)
TheonlydifferenceintheclientsidecodeisthatHTTPclientsuseDialHTTPwhereasTCPclientsuseDial(TCP)
JSONRPC
JSONRPCencodesdatatoJSONinsteadofgobLetsseeanexampleofaGoJSONRPContheserver
RPC
206
packagemain
import(
errors
fmt
net
netrpc
netrpcjsonrpc
os
)
typeArgsstruct
ABint
typeQuotientstruct
QuoRemint
typeArithint
func(tArith)Multiply(argsArgsreplyint)error
reply=argsAargsB
returnnil
func(tArith)Divide(argsArgsquoQuotient)error
ifargsB==0
returnerrorsNew(dividebyzero)
quoQuo=argsAargsB
quoRem=argsAargsB
returnnil
funcmain()
arith=new(Arith)
rpcRegister(arith)
tcpAddrerr=netResolveTCPAddr(tcp1234)
checkError(err)
listenererr=netListenTCP(tcptcpAddr)
checkError(err)
for
connerr=listenerAccept()
iferr=nil
continue
jsonrpcServeConn(conn)
funccheckError(errerror)
iferr=nil
fmtPrintln(FatalerrorerrError())
osExit(1)
JSONRPCisbasedonTCPanddoesntsupportHTTPyet
Theclientsidecode
RPC
207
packagemain
import(
fmt
log
netrpcjsonrpc
os
)
typeArgsstruct
ABint
typeQuotientstruct
QuoRemint
funcmain()
iflen(osArgs)=2
fmtPrintln(UsageosArgs[0]serverport)
logFatal(1)
service=osArgs[1]
clienterr=jsonrpcDial(tcpservice)
iferr=nil
logFatal(dialingerr)
Synchronouscall
args=Args178
varreplyint
err=clientCall(ArithMultiplyargsampreply)
iferr=nil
logFatal(aritherrorerr)
fmtPrintf(Arithdd=dnargsAargsBreply)
varquotQuotient
err=clientCall(ArithDivideargsampquot)
iferr=nil
logFatal(aritherrorerr)
fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)
SummaryGohasgoodsupportforHTTPTPCandJSONRPCimplementationwhichallowustoeasilydevelopdistributedwebapplicationshoweveritisregrettablethatGodoesnthavebuilt-insupportforSOAPRPCalthoughsomeopensourcethird-partypackagesdoofferthis
LinksDirectoryPrevioussectionRESTNextsectionSummary
RPC
208
85SummaryInthischapterIintroducedyoutoseveralmainstreamwebapplicationdevelopmentmodelsInsection81IdescribedthebasicsofnetworkprogrammingsocketsBecauseoftherapidevolutionofnetworktechnologyandinfrastructureandgiventhattheSocketisthecornerstoneofthesechangesyoumustmastertheconceptsbehindsocketprogramminginordertobeacompetentwebdeveloperInsection82IdescribedHTML5WebSocketswhichsupportfull-duplexcommunicationsbetweenclientandserverandeliminatetheneedforpollingwithAJAXInsection83weimplementedasimpleapplicationusingtheRESTarchitecturewhichisparticularlysuitableforthedevelopmentofnetworkAPIsduetotherapidriseofmobileapplicationsIbelievethatRESTfulAPIswillbeanongoingtrendInsection84welearnedaboutGoRPCs
GoprovidesexcellentsupportforthefourkindsofdevelopmentmethodsmentionedaboveNotethatthenetpackageanditssub-packagesistheplacewhereGosnetworkprogrammingtoolsGoresideIfyouwantamorein-depthunderstandingoftherelevantimplementationdetailsyoushouldtryreadingthesourcecodeofthosepackages
LinksDirectoryPrevioussectionRPCNextchapterSecurityandencryption
Summary
209
9SecurityandencryptionSecurityisanextremelyimportantaspectofmostwebapplicationsThistopichasbeengettingmoreandmoreattentionlatelyespeciallyinlightoftherecentCSDNLinkedinandYahoopasswordleaksAsGodeveloperswemustbeawareofvulnerabilitiesinourapplicationsandtakeprecautionsinordertopreventattackersfromtakingoveroursystems
Manyofthesecurityproblemsthatariseinmodernwebapplicationsoriginatefromdataprovidedbythird-partiesForexampleuserinputshouldalwaysbevalidatedandsanitizedbeforebeingstoredassecuredataIfthisisntdonewhenthedataisoutputtedtoaclientitmaycauseacross-sitescriptingattack(XSS)SimilarlyifunsafedataisuseddirectlyasyourapplicationsdatabasequeriesthenyoumaybevulnerabletoSQLinjectionattacksInsections93and94welllookathowtoavoidtheseproblems
Whenusingthird-partydata(whichincludesuser-supplieddata)firstverifytheintegrityofthedatabyfilteringtheinputSection92willdescribehowtofilterinput
UnfortunatelyfilteringinputandescapingoutputdoesnotsolveallsecurityproblemsInsection91wewillexplaincross-siterequestforgery(CSRF)attacksThisisamaliciousexploitwhereunauthorizedcommandsaretransmittedfromauserthatthewebsitetrusts
KeepingconfidentialdataencryptedcanalsohelpyoutosecureyourwebapplicationsInsection95wewilldescribehowtostorepasswordssafelyusingGosencryptionpackage
AgoodhashfunctionmakesithardtofindtwostringsthatwouldproducethesamehashvalueandthisisonewaywithwhichwecanencryptourdataThereisalsotwo-wayencryptionwhereyouuseasecretkeytodecryptencrypteddataInsection96wewilldescribehowtoperformbothone-wayandtwo-wayencryption
LinksDirectoryPreviousChapterChapter8SummaryNextsectionCSRFattacks
Securityandencryption
210
91CSRFattacks
WhatisCSRFCSRFandXSRFbothstandforCross-siterequestforgeryItsalsoknownasaoneclickattackorsessionriding
SohowdoesaCSRFattackworkACSRFattackhappenswhenanattackertricksatrusteduserintoaccessingawebsiteorclickingaURLthattransmitsmaliciousrequests(withouttheuserrsquosconsent)toatargetedwebsiteHeresasimpleexampleusingafewsocialengineeringtricksanattackercouldusetheQQchatsoftwaretofindandsendmaliciouslinkstovictimstargetedattheirusersonlinebankingwebsiteIfthevictimlogsintotheironlinebankaccountanddoesnotexitthenclickingonamaliciouslinksentfromtheattackercouldallowtheattackertostealalloftheusersbankaccountfunds
WhenunderaCSRFattackasingleend-userwithanadministratoraccountcanthreatentheintegrityoftheentirewebapplication
CSRFprincipleThefollowingdiagramprovidesasimpleoverviewofaCSRFattack
Figure91CSRFattackprocess
AscanbeseenfromthefiguretocompleteaCSRFattackthevictimmustcompletethefollowingtwosteps
-1LogintotrustedsiteAandstorealocalCookie-2WithoutgoingthroughexistingsiteAaccessthedangerouslinktositeB
AsareaderyoumaybeaskingIfIdonotmeettheabovetwoconditionsIwillnotbesubjectedtoCSRFattacksYesthisistruehoweveryoucannotguaranteethatthefollowingdoesnotoccur
YoucannotguaranteethatwhenyouareloggedintoasitethesitedidntlaunchanyhiddentabsYoucannotguaranteethatwhenyoucloseyourbrowseryourcookieswillimmediatelyexpireandyourlastsessionwillhaveendedTrustedhightrafficwebsiteswilllikelynothavehiddenvulnerabilitieseasilyexploitablebyCSRFbasedattacks
ThusitcanbedifficultforuserstovisitawebsitethroughalinkandknowthatitwillnotcarryoutunknownoperationsintheformofaCSRFattack
CSRFattacksworkmostlybecauseoftheprocessthroughwhichusersareauthenticatedAlthoughyoucanreasonablyguaranteethatarequestoriginatesfromausersbrowserthereisnoguaranteethattheusergrantedapprovalfortherequest
HowtopreventCSRFattacksYoumightbealittlescaredafterreadingthesectionaboveButfearisagoodthingItwillforceyoutoeducateyourselfonhowtopreventvulnerabilitieslikethisfromhappeningtoyou
PreventativemeasuresagainstCSRFattackscanbetakenonboththeserverandclientsidesofawebapplicationHoweverCSRFattacksaremosteffectivelythwartedontheserverside
TherearemanywaysofpreventingCSRFattacksontheserversideMostapproachesstemfromthefollowingtwoaspects
1 MaintainingproperuseofGETPOSTandcookies
CSRFattacks
211
2 Includingapseudo-randomnumberwithnon-GETrequests
InthepreviouschapteronRESTwesawhowmostwebapplicationsarebasedonGETandPOSTHTTPrequestsandthatcookieswereincludedalongwiththeserequestsWegenerallydesignapplicationsaccordingtothefollowingprinciples
1 GETiscommonlyusedtoviewinformationwithoutalteringanydata
2 POSTisusedinplacingorderschangingthepropertiesofaresourceorperformingothertasks
ImnowgoingtousetheGolanguagetoillustratehowtorestrictaccesstoresourcesmethods
muxGet(useruidgetuser)
muxPost(useruidmodifyuser)
SincewevestipulatedthatmodificationscanonlyusePOSTwhenaGETmethodisissuedinsteadofaPOSTwecanrefusetorespondtotherequestAccordingtothefigureaboveattacksutilizingGETasaCSRFexploitcanbepreventedIsthisenoughtopreventallpossibleCSRFattacksOfcoursenotbecausePOSTscanalsobeforged
Weneedtoimplementasecondstepwhichis(inthecaseofnon-GETrequests)toincreasethelengthofthepseudo-randomnumberincludedwiththerequestThisusuallyinvolvessteps
Foreachusergenerateauniquecookietokenwithapseudo-randomvalueAllformsmustcontainthesamepseudo-randomvalueThisproposalisthesimplestonebecauseintheoryanattackercannotreadthirdpartycookiesAnyformthatanattackermaysubmitwillfailthevalidationprocesswithoutknowingwhattherandomvalueisDifferentformscontaindifferentpseudo-randomvaluesasweveintroducedinsection44HowtopreventmultipleformsubmissionWecanreusetherelevantcodefromthatsectiontomeetourneeds
Generatingarandomnumbertoken
h=md5New()
ioWriteString(hstrconvFormatInt(crutime10))
ioWriteString(hganraomaxxxxxxxxx)
token=fmtSprintf(xhSum(nil))
t_=templateParseFiles(logingtpl)
tExecute(wtoken)
Outputtoken
ltinputtype=hiddenname=tokenvalue=gt
Authenticationtoken
rParseForm()
token=rFormGet(token)
iftoken=
Verificationtokenoflegitimacy
Else
Errortokendoesnotexist
WecanusetheprecedingcodetosecureourPOSTsYoumightbewonderinginaccordancewithourtheorywhethertherecouldbesomewayforamaliciousthirdpartytosomehowfigureoutoursecrettokenvalueInfactcrackingitisbasicallyimpossible-successfullycalculatingthecorrectstringvalueusingbruteforcemethodsneedsabout2tothe11thtime
Summary
CSRFattacks
212
Cross-siterequestforgeryalsoknownasCSRFisaverydangerouswebsecuritythreatItisknowninwebsecuritycirclesasasleepinggiantsecurityissueasyoucantellCSRFattackshavequitethereputationThissectionnotonlyintroducedcross-siterequestforgeryitselfbutfactorsunderlyingthisvulnerabilityItconcludeswithsomesuggestionsandmethodsforpreventingsuchattacksIhopethissectionwillhaveinspiredyouasareadertowritebetterandmoresecurewebapplications
LinksDirectoryPrevioussectionSecurityandencryptionNextsectionFilterinputs
CSRFattacks
213
92FilteringinputsFilteringuserdataisonewaywecanimprovethesecurityofourwebappsusingittoverifythelegitimacyofincomingdataAlloftheinputdataisfilteredinordertoavoidmaliciouscodeordatafrombeingmistakenlyexecutedorstoredMostwebapplicationvulnerabilitiesariseformneglectingtofilterinputdataandnaivelytrustingit
Ourintroductiontofilteringdataisdividedintothreesteps
1 identifyingthedataweneedtofilterthedatatofigureoutwhereitoriginatedfrom2 filteringofthedataitselfweneedtofigureoutwhatkindofdatawehavereceived3 distinguishbetweenfiltered(sanitized)andtainteddataafterthedatahasbeenfilteredwecanbeassuredthatitis
secure
IdentifyingdataIdentifyingthedataisourfirststepbecausemostofthetimeasmentionedwedontknowwhereitoriginatesfromWithoutthisknowledgewewouldbeunabletoproperlyfilteritThedatahereisprovidedinternallyallfromnon-codedataForexamplealldatacomesfromclientshoweverclientsthatareusersarenottheonlyexternalsourcesofdataAdatabaseinterfaceprovidingthirdpartydatacouldalsobeanexternaldatasource
DatathathasbeenenteredbyauserisveryeasytorecognizeinGoWeuserParseFormaftertheuserPOSTsaformtogetallofthedatainsidetherFormOthertypesofinputaremuchhardertoidentifyForexampleinrHeadersmanyoftheelementsareoftenmanipulatedbytheclientItcanoftenbedifficulttoidentifywhichoftheseelementshavebeenmanipulatedbyclientssoitsbesttoconsiderallofthemashavingbeentaintedTherHeaderGet(Accept-Charset)headerfieldforinstanceisalsoconsideredasuserinputalthoughthesearetypicallyonlymanipulatedbybrowsers
FilteringdataIfweknowthesourceofthedatawecanfilteritFilteringisabitofaformaluseofthetermTheprocessisknownbymanyothertermssuchasinputcleaningvalidationandsanitizationDespitethefactthatthesetermsdiffersomewhatintheirmeaningtheyallrefertothesamethingtheprocessofpreventingillegaldatafrommakingitswayintoyourapplications
TherearemanywaystofilterdatasomeofwhicharelesssecurethanothersThebestmethodistocheckwhetherornotthedataitselfmeetsthelegalrequirementsdictatedbyyourapplicationWhenattemptingtodosoitsveryimportantnottomakeanyattemptsatcorrectingtheillegaldatathiscouldallowmalicioususerstomanipulateyourvalidationrulesfortheirownneedsaltogetherdefeatingthepurposeoffilteringthedatainthefirstplaceHistoryhasproventhatattemptingtocorrectinvaliddataoftenleadstosecurityvulnerabilitiesLetstakealookatanoverlysimpleexampleforillustrationpurposesSupposethatabankingsystemasksuserstosupplyasecure6digitpasswordThesystemvalidatesthelengthofallpasswordsOnemightnaivelywriteavalidationrulethatcorrectspasswordsofillegallengthsIfapasswordisshorterthanthelegallengthfillintheremainingdigitswith0sThissimplerulewouldallowattackerstoguessjustthefirstfewdigitsofapasswordtosuccessfullygainaccesstouseraccounts
Wecanuseseverallibrariestohelpustofilterdata
ThestrconvpackagecanhelpustoconvertstringsinputbyusersintospecifictypessincerFormsaremapsofstringvaluesSomecommonstringconversionsprovidedbystrconvareAtoiParseBoolParseFloatandParseIntGosstringspackagecontainssomefilterfunctionslikeTrimToLowerandToTitlewhichcanhelpustoobtaindatainaspecificformatsaccordingtoourneedsGosregexppackagecanbeusedtohandlecaseswhicharemorecomplexinnaturesuchasdeterminingwhetheraninputisanemailaddressabirthdayetc
Filterinputs
214
FilteringincomingdatainadditiontoauthenticationcanbequiteeffectiveLetsaddanothertechniquetoourrepertoirecalledwhitelistingWhitelistingisagoodwayofconfirmingthelegitimacyofincomingdataUsingthismethodifanerroroccursitcanonlymeanthattheincomingdataisillegalandnottheoppositeOfcoursewedontwanttomakeanymistakesinourwhitelistbyfalselylabellinglegitimatedataasillegalbutthisscenarioismuchbetterthanillegaldatabeinglabeledaslegitimateandthusmuchmoresecure
DistinguishingbetweenfilteredandtainteddataIfyouhavecompletedtheabovestepsthejoboffilteringdatahasbasicallybeencompletedHoweverwhenwritingwebapplicationswealsoneedtodistinguishbetweenfilteredandtainteddatabecausedoingsocanguaranteetheintegrityofourdatafilteringprocesswithoutaffectingtheinputdataLetsputallofourfiltereddataintoaglobalmapvariablecalledCleanMapThentwoimportantstepsarerequiredtopreventcontaminationviadatainjection
EachrequestmustinitializeCleanMapasanemptymapPreventvariablesfromexternaldatasourcesnamedCleanMapfrombeingintroducedintotheapp
Nextletsuseanexampleformtoreinforcetheseconcepts
ltformaction=whoamimethod=POSTgt
WhoamI
ltselectname=namegt
ltoptionvalue=astaxiegtastaxieltoptiongt
ltoptionvalue=herrygtherryltoptiongt
ltoptionvalue=marrygtmarryltoptiongt
ltselectgt
ltinputtype=submitgt
ltformgt
IndealingwiththistypeofformitcanbeveryeasytomakethemistakeofthinkingthatuserswillonlybeabletosubmitoneofthethreeselectoptionsInfactPOSToperationscaneasilybesimulatedbyattackersForexamplebysubmittingthesameformwithname=attackamalicioususercouldintroduceillegaldataintooursystemWecanuseasimplewhitelisttocounterthesetypesofattacks
rParseForm()
name=rFormGet(name)
CleanMap=make(map[string]interface0)
ifname==astaxie||name==herry||name==marry
CleanMap[name]=name
TheabovecodeinitializesaCleanMapvariableandanameisonlyassignedaftercheckingitagainstaninternalwhitelistoflegitimatevalues(astaxieherryandmarryinthiscase)WestorethedataintheCleanMapinstancesoyoucanbesurethatCleanMap[name]holdsavalidatedvalueAnycodewishingtoaccessthisvaluecanthenfreelydosoWecanalsoaddanadditionalelsestatementtotheaboveifwhitelistfordealingwithillegaldataapossibilitybeingthattheformwasdisplayedwithanerrorDonottrytobetooaccommodatingthoughoryouruntheriskofaccidentallycontaminatingyourCleanMap
TheabovemethodforfilteringdataagainstasetofknownlegitimatevaluesisveryeffectiveThereisanothermethodforcheckingwhetherornotincomingdataconsistsoflegalcharactersusingregexphoweverthiswouldbeineffectualintheabovecasewherewerequirethatthenamebeanoptionfromtheselectForexampleyoumayrequirethatusernamesonlyconsistoflettersandnumbers
rParseForm()
username=rFormGet(username)
CleanMap=make(map[string]interface0)
ifok_=regexpMatchString(^[a-zA-Z0-9]$username)ok
CleanMap[username]=username
Filterinputs
215
SummaryDatafilteringplaysavitalroleinthesecurityofmodernwebapplicationsMostsecurityvulnerabilitiesaretheresultofimproperlyfilteringdataorneglectingtoproperlyvalidateitBecausetheprevioussectiondealtwithCSRFattacksandthenexttwowillbeintroducingXSSattacksandSQLinjectiontherewasnonaturalsegueintodealingwithatopicasimportantasdatasanitizationsointhissectionwepaidspecialattentiontoit
LinksDirectoryPrevioussectionCSRFattacksNextsectionXSSattacks
Filterinputs
216
93XSSattacksWiththedevelopmentofInternettechnologywebapplicationsareoftenpackedwithdynamiccontenttoimproveuserexperienceDynamiccontentiscontentthatreactsandchangesaccordingtouserrequestsandactionsDynamicsitesareoftensusceptibletocross-sitescriptingattacks(oftenreferredtobysecurityexpertsinitsabbreviatedformXSS)somethingwhichstaticwebsitesarecompletelyunaffectedby
WhatisXSSAsmentionedthetermXSSisanacronymforCross-SiteScriptingwhichisatypeofattackcommononthewebInordernottoconfuseitwithanothercommonwebacronymCSS(CascadingStyleSheets)weuseanXinsteadofaCforthecrossincross-sitescriptingXSSisacommonwebsecurityvulnerabilitywhichallowsattackerstoinjectmaliciouscodeintowebpagesUnlikemosttypesofattackswhichgenerallyinvolveonlyanattackerandavictimXSSinvolvesthreepartiesanattackeraclientandawebapplicationThegoalofanXSSattackistostealcookiesstoredonclientsbywebapplicationsforthepurposeofreadingsensitiveclientinformationOnceanattackergetsaholdofthisinformationtheycanimpersonateusersandinteractwithwebsiteswithouttheirknowledgeorapproval
XSSattackscanusuallybedividedintotwocategoriesoneisastoredXSSattackThisformofattackariseswhenusersareallowedtoinputdataontoapublicpagewhichafterbeingsavedbytheserverwillbereturned(unescaped)tootherusersthathappentobebrowsingitSomeexamplesofthetypesofpagesthatareoftenaffectedincludecommentsreviewsblogpostsandmessageboardsTheprocessoftengoeslikethisanattackerenterssomehtmlfollowedbyahiddenltscriptgttagcontainingsomemaliciouscodethenhitssaveThewebapplicationsavesthistothedatabaseWhenanotheruserrequeststhispagetheapplicationqueriesthistainteddatafromthedatabaseandservesthepagetotheuserTheattackersscriptthenexecutesarbitrarycodeontheclientscomputer
TheothertypeisareflectedXSSattackThemainideaistoembedamaliciousscriptdirectlyintothequeryparametersofaURLaddressAserverthatimmediatelyparsesthisdataintoapageofresultsandreturnsit(totheclientwhomadetherequest)unsanitizedcanunwittinglycausetheclientscomputertoexecutethiscodeAnattackercansendauseralegitimatelookinglinktoatrustedwebsitewiththeencodedpayloadclickingonthislinkcancausetheusersbrowsertoexecutethemaliciousscript
XSSpresentthemainmeansandendsasfollows
TheftofcookiesaccesstosensitiveinformationTheuseofembeddedFlashthroughcrossdomainpermissionscanalsobeusedbyanattackertoobtainhigheruserprivilegesThisalsoappliesforothersimilarattackvectorssuchasJavaandVBScriptTheuseofiframesframesXMLHttpRequestsetccanallowanattackertoassumetheidentityofausertoperformadministrativeactionssuchasmicro-bloggingaddingfriendssendingprivatemessagesandotherroutineoperationsAwhileagotheSinamicrobloggingplatformsufferedfromthistypeofXSSvulnerabilityWhenmanyusersvisitapageaffectedbyanXSSattacktheeffectonsomesmallersitescanbecomparabletothatofaDDoSattack
XSSprinciplesWebapplicationsthatreturnrequesteddatatouserswithoutfirstinspectingandfilteringitcanallowmalicioususerstoinjectscripts(typicallyembeddedinsideHTMLwithinltscriptgttags)ontootherusersbrowsersWhenthismaliciouscodeisrenderedonausersbrowserwithoutfirsthavingbeenescapedfromtheusersbrowserwillinterpretthiscodethisisthedefinitionofanXSSattackandthistypeofmistakeistheleadingcauseofXSSvulnerabilities
LetsgothroughtheprocessofareflectiveXSSattackLetssaytheresawebsitethatoutputsausersnameaccordingtotheURLqueryparametersaccessthefollowingURLhttp127001name=astaxiewillcausetheservertooutputthefollowing
XSSattacks
217
helloastaxie
Letssaywepassthefollowingparameterinsteadaccessingthesameurlhttp127001name=ltscriptgtalert(astaxiexss)ltscriptgtIfthiscausesthebrowsertoproduceanalertpop-upboxwecanconfirmthatthesiteisvulnerabletoXSSattacksSohowdomalicioususersstealcookiesusingthesametypeofattack
JustlikebeforewehaveaURL
http127001
name=amp60scriptamp62documentlocationhref=httpwwwxxxcomcookie+documentcookieamp60scriptamp62
ByclickingonthisURLyoudbesendingthecurrentcookietothespecifiedsitewwwxxxcomYoumightbewonderingwhywouldanybodyclickonsuchastrangelookingURLinthefirstplaceWhileitstruethatthiskindofURLwillmakemostpeopleskepticalifanattackerweretouseoneofthemanypopularURLshorteningservicestoobscureitwouldyoustillbeabletoseeitMostattackerswouldobfuscatetheURLinonewayoranotherandyoudonlyknowthelegitimacyofthelinkafterclickingonitHoweverbythispointcookiedatawillhavealreadybeensenttothe3rdpartywebsitecompromisingyoursensitiveinformationYoucanusetoolslikeWebsleuthtoauditthesecurityofyourwebapplicationsforthesetypesofvulnerabilities
ForamoredetailedanalysisonanXSSattackhavealookatthearticle[SinamicrobloggingXSSeventanalysis](httpwwwrisingcomcnnewsletternews2011-08-189621html)
HowtopreventXSSTheanswerissimplenevertrustuserinputandalwaysfilteroutallspecialcharactersinanyinputdatayoumayreceiveThiswilleliminatethemajorityofXSSattacks
UsethefollowingtechniquestodefendagainstXSSattacks
Filterspecialcharacters
OnewaytoavoidXSSistofilteruser-suppliedcontentTheGolanguageprovidessomeHTMLfilteringfunctionsinitstexttemplatepackgesuchasHTMLEscapeStringandJSEscapeStringtonameafew
SpecifythecontenttypeinyourHTTPheaders
wHeader()Set(Content-Typetextjavascript)
Thisallowsclientbrowserstoparsetheresponseasjavascriptcode(applyingtheneccessaryfilters)insteadofrenderingthecontentinanunspecifiedandpotentiallydangerousmanner
SummaryIntroducingXSSvulnerabilitiesisaveryrealhazardwhendevelopingwebapplicationsItisimportanttoremembertofilteralldataespeciallybeforeoutputtingittoclientsthisisnowawell-establishedmeansofpreventingXSS
LinksDirectoryPrevioussectionFilterinputsNextsectionSQLinjection
XSSattacks
218
94SQLinjection
WhatisSQLinjectionSQLinjectionattacksare(asthenamewouldsuggest)oneofthemanytypesofscriptinjectionattacksInwebdevelopmentthesearethemostcommonformofsecurityvulnerabilitiesAttackerscanuseittoobtainsensitiveinformationfromdatabasesandaspectsofanattackcaninvolveaddinguserstothedatabaseexportingprivatefilesandevenobtainingthehighestsystemprivilegesfortheirownnefariouspurposes
SQLinjectionoccurswhenwebapplicationsdonoteffectivelyfilteroutuserinputleavingthedoorwideopenforattackerstosubmitmaliciousSQLquerycodetotheserverApplicationsoftenreceiveinjectedcodeaspartofanattackersinputwhichaltersthelogicoftheoriginalqueryinsomewayWhentheapplicationattemptstoexecutethequerytheattackersmaliciouscodeisexecutedinstead
SQLinjectionexamplesManywebdevelopersdonotrealizehowSQLqueriescanbetamperedwithandmayholdthemisconceptionthattheyaretrustedcommandsAseveryoneknowsSQLqueriesareabletocircumventaccesscontrolstherebybypassingthestandardauthenticationandauthorizationchecksWhatsmoreitspossibletorunSQLqueriesthroughcommandsatthelevelofthehostsystem
LetshavealookatsomerealexamplestoexplaintheprocessofSQLinjectionindetail
Considerthefollowingsimpleloginform
ltformaction=loginmethod=POSTgt
ltpgtUsernameltinputtype=textname=usernamegtltpgt
ltpgtPasswordltinputtype=passwordname=passwordgtltpgt
ltpgtltinputtype=submitvalue=Logingtltpgt
ltformgt
Ourformprocessingmightlooklikethis
username=rFormGet(username)
password=rFormGet(password)
sql=SELECTFROMuserWHEREusername=+username+ANDpassword=+password+
Iftheuserinputsausernameorpasswordas
myuserorfoo=foo--
ThenourSQLbecomesthefollowing
SELECTFROMuserWHEREusername=myuserorfoo=foo--ANDpassword=xxx
InSQLanythingafter--isacommentThusinsertingthe--astheattackerdidabovealtersthequeryinafatalwayallowinganattackertosuccessfullyloginasauserwithoutavalidpassword
FarmoredangerousexploitsexistforMSSQLSQLinjectionsandsomecanevenperformsystemcommandsThefollowingexampleswilldemonstratehowterribleSQLinjectionscanbeinsomeversionsofMSSQLdatabases
sql=SELECTFROMproductsWHEREnameLIKE+prod+
DbExec(sql)
SQLinjection
219
Ifanattackersubmitsaexecmasterxp_cmdshellnetusertesttestpassADD--astheprodvariablethenthesqlwillbecome
sql=SELECTFROMproductsWHEREnameLIKEaexecmasterxp_cmdshellnetusertesttestpassADD--
TheMSSQLServerexecutestheSQLstatementincludingthecommandsintheusersuppliedprodvariablewhichaddsnewuserstothesystemIfthisprogramisrunasisandtheMSSQLSERVERservicehassufficientprivilegesanattackercanregisterasystemaccounttoaccessthismachine
AlthoughtheexamplesabovearetiedtoaspecificdatabasesystemthisdoesnotmeanthatotherdatabasesystemscannotbesubjectedtosimilartypesofattacksTheprinciplesbehindSQLinjectionattacksremainthesamethoughthemethodwithwhichtheyareperpetratedmayvary
HowtopreventSQLinjectionYoumightbethinkingthatanattackerwouldhavetoknowinformationaboutthetargetdatabasesstructureinordertocarryoutanSQLinjectionattackWhilethisistrueitsdifficulttoguaranteethatanattackerwontbeabletofindthisinformationandoncetheygetitthedatabasecanbecompromisedIfyouareusingopensourcesoftwaretoaccessthedatabasesuchasaforumapplicationintruderscaneasilygettherelatedcodeObviouslywithpoorlydesignedcodethesecurityrisksareevengreaterDiscuzphpwindandphpcmsaresomeexamplesofpopularopensourceprogramsthathavebeenvulnerabletoSQLinjectionattacks
TheseattackshappentosystemswheresafetyprecautionsarenotprioritizedWevesaiditbeforewellsayitagainnevertrustanykindofinputespeciallyuserdataThisincludesdatacomingfromselectionboxeshiddeninputfieldsorcookiesAsourfirstexampleabovehasshownevensupposedlynormalqueriescancausedisasters
SQLinjectionattackscanbedevastating-howcandoweevenbegintodefendagainstthemThefollowingsuggestionsareagoodstartingpointforpreventingSQLinjection
1 Strictlylimitpermissionsfordatabaseoperationssothatusersonlyhavetheminimumsetofpermissionsrequiredtoaccomplishtheirworkthusminimizingtheriskofdatabaseinjectionattacks
2 CheckthatinputdatahastheexpecteddataformatandstrictlylimitthetypesofvariablesthatcanbesubmittedThiscaninvolveregexpmatchingorusingthestrconvpackagetoconvertstringsintootherbasictypesforsanitizationandevaluation
3 Transcodeorescapefrompairsofspecialcharacters(ampetc)beforepersistingthemintothedatabaseGostexttemplatepackagehasaHTMLEscapeStringfunctionthatcanbeusedtoreturnescapedHTML
4 UseyourdatabasesparameterizedqueryinterfaceParameterizedstatementsuseparametersinsteadofconcatenatinguserinputvariablesinembeddedSQLstatementsinotherwordstheydonotdirectlyspliceSQLstatementsForexampleusingthePreparefunctioninGosdatabasesqlpackagewecancreatepreparedstatementsforlaterexecutionwithQueryorExec(querystringargsinterface)
5 BeforereleasingyourapplicationthoroughlytestitusingprofessionaltoolsfordetectingSQLinjectionvulnerabilitiesandtorepairthemiftheyexistTherearemanyonlineopensourcetoolsthatdojustthissuchassqlmapSQLninjatonameafew
6 AvoidprintingoutSQLerrorinformationonpublicwebpagesAttackerscanusetheseerrormessagestocarryoutSQLinjectionattacksExamplesofsucherrorsaretypeerrorsfieldsnotmatchingerrorsoranyerrorscontainingSQLstatements
SummaryThroughtheaboveexampleswevelearnedthatSQLinjectionisaveryrealandverydangerouswebsecurityvulnerabilityWhenwewritewebapplicationweshouldpayattentiontoeverylittledetailandtreatsecurityissueswiththeutmostcareDoingsowillleadtobetterandmoresecurewebapplicationsandcanultimatelybethedetermingfactorinwhetherornotyourapplicationsucceeds
SQLinjection
220
LinksDirectoryPrevioussectionXSSattacksNextsectionPasswordstorage
SQLinjection
221
95PasswordstorageOvertheyearsmanywebsiteshavesufferedfrombreachesinuserpassworddataEventopinternetcompaniessuchasLinkedinandCSDNnethavebeenaffectedTheimpactoftheseeventshasbeenfeltacrosstheentireinternetandcannotbeunderestimatedThisisespeciallythecasefortodaysinternetuserswhooftenadoptthehabitofusingthesamepasswordformanydifferentwebsites
AswebdeveloperswehavemanychoiceswhenitcomestoimplementingapasswordstorageschemeHoweverthisfreedomisoftenadoubleedgedswordSowhatarethecommonpitfallsandhowcanweavoidfallingintothem
BadsolutionCurrentlythemostfrequentlyusedpasswordstorageschemeistoone-wayhashplaintextpasswordsbeforestoringthemThemostimportantcharacteristicofone-wayhashingisthatitisnotfeasibletorecovertheoriginaldatagiventhehasheddata-hencetheone-wayinone-wayhashingCommonlyusedcryptographicone-wayhashalgorithmsincludeSHA-256SHA-1MD5andsoon
YoucaneasilyusethethreeaforementionedhashingalgorithmsinGoasfollows
importcryptosha256
h=sha256New()
ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)
fmtPrintf(xhSum(nil))
importcryptosha1
h=sha1New()
ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)
fmtPrintf(xhSum(nil))
importcryptomd5
h=md5New()
ioWriteString(h需要加密的密码)
fmtPrintf(xhSum(nil))
Therearetwokeyfeaturesofone-wayhashing
1)givenaone-wayhashofapasswordtheresultingsummaryisalwaysuniquelydetermined2)calculationspeedAstechnologyadvancesitonlytakesasecondtocompletebillionsofone-wayhashcalculations
GiventhecombinationoftheabovetwocharacteristicsandtakingintoaccountthefactthatthemajorityofpeopleusesomecombinationofcommonpasswordsanattackercancomputeacombinationofallthecommonpasswordsEventhoughthepasswordsyoustoreinyourdatabasemaybehashvaluesonlyifattackersgainaccesstothisdatabasetheycancomparethestoredhashestotheirprecomputedhashestoobtainthecorrespondingpasswordsThistypeofattackreliesonwhatistypicallycalledarainbowtable
Wecanseethathashinguserdatausingone-wayhashesmaynotbeenoughOnceawebsitesdatabasegetsleakedtheusersoriginalpasswordcouldpotentiallyberevealedtotheworld
GoodsolutionThemethodmentionedabovemayhavebeensecureenoughtothwartmosthackingattemptsafewyearsagosincemostattackerswouldnothavehadthecomputingresourcestocomputelargerainbowtablesHoweverwiththeriseofparallelcomputingcapabilitiesthesetypesofattacksarebecomingmoreandmorefeasible
Passwordstorage
222
HowdowesecurelystoreapasswordsothatitcannotbedecipheredbyathirdpartygivenreallifelimitationsintimeandmemoryresourcesThesolutionistocalculateahashedpasswordtodeliberatelyincreasetheamountofresourcesandtimeitwouldtaketocrackitWewanttodesignahashsuchthatnobodycouldpossiblyhavetheresourcesrequiredtocomputetherequiredrainbowtable
VerysecuresystemsutilizehashalgorithmsthattakeintoaccountthetimeandresourcesitwouldrequiretocomputeagivenpassworddigestThisallowsustocreatepassworddigeststhatarecomputationallyexpensivetoperformonalargescaleThegreatertheintensityofthecalculationthemoredifficultitwillbeforanattackertopre-computerainbowtables-somuchsothatitmayevenbeinfeasibletotry
InGoitsrecommendedthatyouusethebcryptpackage
Thepackagessourcecodecanbefoundatthefollowinglinkhttpsgithubcomgolangcryptoblobmasterbcryptbcryptgo
Hereisanexamplecodesnippetwhichcanbeusedtohashstoreandvalidateuserpasswords
packagemain
import(
fmt
log
golangorgxcryptobcrypt
)
funcmain()
userPassword1=someuser-providedpassword
Generatehashtostorefromuserpassword
hasherr=bcryptGenerateFromPassword([]byte(userPassword1)bcryptDefaultCost)
iferr=nil
TODOProperlyhandleerror
logFatal(err)
fmtPrintln(Hashtostorestring(hash))
Storethishashsomewhereeginyourdatabase
Afterawhiletheuserwantstologinandyouneedtocheckthepasswordheentered
userPassword2=someuser-providedpassword
hashFromDatabase=hash
Comparingthepasswordwiththehash
iferr=bcryptCompareHashAndPassword(hashFromDatabase[]byte(userPassword2))err=nil
TODOProperlyhandleerror
logFatal(err)
fmtPrintln(Passwordwascorrect)
SummaryIfyoureworriedaboutthesecurityofyouronlinelifeyoucantakethefollowingsteps
1)AsaregularinternetuserwerecommendusingLastPassforpasswordstorageandgenerationondifferentsitesusedifferentpasswords
2)AsaGowebdeveloperwestronglysuggestthatyouuseoneoftheprofessionalwelltestedmethodsaboveforstoringuserpasswords
LinksDirectory
Passwordstorage
223
PrevioussectionSQLinjectionNextsectionEncryptanddecryptdata
Passwordstorage
224
96EncryptinganddecryptingdataTheprevioussectiondescribeshowtosecurelystorepasswordsbutsometimesitmightbeneccessarytomodifysomesensitiveencrypteddatathathasalreadybeenstoredintoourdatabaseWhendatadecryptionisrequiredweshoulduseasymmetricencryptionalgorithminsteadoftheone-wayhashingtechniqueswevepreviouslycovered
AdvancedencryptionanddecryptionTheGolanguagesupportssymmetricencryptionalgorithmsinitscryptopackageDonotuseanythingexceptAESinGCMmodeifyoudontknowwhatyouredoing
cryptoaespackageAES(AdvancedEncryptionStandard)alsoknownasRijndaelencryptionmethodisusedbytheUSfederalgovernmentasablockencryptionstandard
InthefollowingexamplewedemonstratehowtoencryptdatausingAESinGCMmode
Encryptanddecryptdata
225
packagemain
import(
cryptoaes
cryptocipher
cryptorand
errors
fmt
io
log
)
funcmain()
text=[]byte(MynameisAstaxie)
key=[]byte(the-key-has-to-be-32-bytes-long)
ciphertexterr=encrypt(textkey)
iferr=nil
TODOProperlyhandleerror
logFatal(err)
fmtPrintf(s=gtxntextciphertext)
plaintexterr=decrypt(ciphertextkey)
iferr=nil
TODOProperlyhandleerror
logFatal(err)
fmtPrintf(x=gtsnciphertextplaintext)
funcencrypt(plaintext[]bytekey[]byte)([]byteerror)
cerr=aesNewCipher(key)
iferr=nil
returnnilerr
gcmerr=cipherNewGCM(c)
iferr=nil
returnnilerr
nonce=make([]bytegcmNonceSize())
if_err=ioReadFull(randReadernonce)err=nil
returnnilerr
returngcmSeal(noncenonceplaintextnil)nil
funcdecrypt(ciphertext[]bytekey[]byte)([]byteerror)
cerr=aesNewCipher(key)
iferr=nil
returnnilerr
gcmerr=cipherNewGCM(c)
iferr=nil
returnnilerr
nonceSize=gcmNonceSize()
iflen(ciphertext)ltnonceSize
returnnilerrorsNew(ciphertexttooshort)
nonceciphertext=ciphertext[nonceSize]ciphertext[nonceSize]
returngcmOpen(nilnonceciphertextnil)
Encryptanddecryptdata
226
CallingtheabovefunctionaesNewCipher(whose[]bytekeyparametermustbe1624or32correspondingtotheAES-128AES-192orAES-256algorithmsrespectively)returnsacipherBlockInterfacethatimplementsthreefunctions
typeBlockinterface
BlockSizereturnstheciphersblocksize
BlockSize()int
Encryptencryptsthefirstblockinsrcintodst
Dstandsrcmaypointatthesamememory
Encrypt(dstsrc[]byte)
Decryptdecryptsthefirstblockinsrcintodst
Dstandsrcmaypointatthesamememory
Decrypt(dstsrc[]byte)
ThesethreefunctionsimplementencryptionanddecryptionoperationsseetheGodocumentationforamoredetailedexplanation
SummaryThissectiondescribesencryptionalgorithmswhichcanbeusedindifferentwaysaccordingtoyourwebapplicationsencryptionanddecryptionneedsForapplicationswithevenbasicsecurityrequirementsitisrecommendedtouseAESinGCMmode
LinksDirectoryPreviousstorepasswordsNextSummary
Encryptanddecryptdata
227
97SummaryInthischapterwevedescribedCSRFXSSandSQLinjectionbasedattacksMostwebapplicationsarevulnerabletothesetypesofattacksduetoalackofadequateinputfilteringonthepartoftheapplicationSoinadditiontointroducingtheprinciplesbehindtheseattackswevealsointroducedafewtechniquesforeffectivelyfilteringuserdataandpreventingtheseattacksfromevertakingplaceWethendiscussedafewmethodsforsecurelystoringuserpasswordsfirstintroducingbasicone-wayhashingforwebapplicationswithloosesecurityrequirementsthenpasswordsaltingandencryptionalgorithmsformoreseriousapplicationsFinallywebrieflydiscussedtwo-wayhashingandtheencryptionanddecryptionofsensitivedataWelearnedthattheGolanguageprovidespackagesforthreesymmetricencryptionalgorithmsbase64AESandDESThepurposeofthischapteristohelpreadersbecomemoreconsciousofthesecurityissuesthatexistinmoderndaywebapplicationsHopefullyitcanhelpdeveloperstoplananddesigntheirwebapplicationsalittlemorecarefullysotheycanwritesystemsthatareabletopreventhackersfromexploitinguserdataTheGolanguagehasalargeandwelldesignedanti-attacktoolkitandeveryGodevelopershouldtakefulladvantageofthesepackagestobettersecuretheirwebapplications
LinksDirectoryPrevioussectionEncryptanddecryptdataNextchapterInternationalizationandlocalization
Summary
228
10InternationalizationandlocalizationInordertoadapttotheincreasingglobalizationoftheinternetasdeveloperswemaysometimesneedtobuildmultilingualinternationalwebapplicationsThismeansthatsomepageswillappearindifferentlanguagesaccordingtouserregionsandperhapstheUIandUXwillalsobeadaptedtoshowdifferenteffectsbasedonlocalholidaysorcultureForexampleatruntimetheapplicationwillbeabletorecognizeandprocessrequestscomingfromdifferentgeographicalregionsandrenderpagesinthelocaldialectordisplaydifferentuserinterfaceAscompetentdeveloperswedontwanttohavetomanuallymodifyourapplicationssourcecodetocatertoeverypossibleregionoutthereWhenanapplicationneedstoaddsupportforanewlanguageweshouldbeabletosimplydropintheappropriatelanguagepackandbedonewithit
Inthissectionwellbetalkingaboutinternationalizationandlocalization(usuallyexpressedasi18nandL10Nrespectively)InternationalizationistheprocessofdesigningapplicationsthatareflexibleenoughtobeservedtomultipleregionsaroundtheworldInsomewayswecanthinkofinternationalizationassomethingthathelpstofacilitatelocalizationwhichistheadaptationofawebapplicationscontentanddesigntosuitthelanguageorculturalneedsofspecificlocales
CurrentlyGosstandardpackagedoesnotprovidei18nsupportbuttherearesomeusefulandrelativelysimplethird-partyimplementationsavailableInthischapterwellbeusingtheopen-sourcego-i18nlibrarytosupportinternationalizationinourexamples
WhenwetalkaboutmakingourwebapplicationsinternationalwemeanthateachwebpageshouldbeconstructedwithlocalespecificinformationandassembledwiththecorrespondinglocalstringstimeandcurrencyformatsetcThisinvolvesthreethings
1 howtodeterminetheuserslocale
2 howtosavestringsorotherinformationassociatedwiththelocale
3 howtoembedstringsandotherinformationaccordingtotheuserslocale
InthefirstsectionwelldescribehowtodetectandsetthecorrectlocaleinordertoallowwebsiteusersaccesstotheirlanguagespecificpagesThesecondsectiondescribeshowtohandleorstorestringscurrenciestimesdatesandotherlocalerelatedinformationFinallythethirdsectionwilldescribehowtointernationalizeyourwebapplicationmorespecificallywelldiscusshowtoreturndifferentpageswithlocaleappropriatecontentThroughthesethreesectionswellbeabletosupportfulli18ninourwebapplications
LinksDirectoryPreviousChapterChapter9SummaryNextsectionSettingthedefaultregion
Internationalizationandlocalization
229
101Settingthedefaultregion
FindingoutthelocaleAlocaleisasetofdescriptorsforaparticulargeographicalregionandcanincludespecificlanguagehabitstextformattingculturalidiomsandamultitudeofothersettingsAlocalesnameisusuallycomposedofthreepartsFirst(andmandatory)isthelocaleslanguageabbreviationsuchasenforEnglishorzhforChineseThesecondpartisanoptionalcountryspecifierandfollowsthefirstwithanminussignThisspecifierallowswebapplicationstodistinguishbetweendifferentcountrieswhichspeakthesamelanguagesuchasen-USforUSEnglishanden-GBforBritishEnglishThelastpartisanotheroptionalspecifierandisaddedtothelocalewithaperiodItspecifieswhichcharactersettouseforinstancezh-CNgb2312specifiesthegb2312charactersetforChinese
GodefaultstotheUTF-8encodingsetsoi18ninGoapplicationsdonotneedtoconsiderthelastparameterThusinourexampleswellonlyusethefirsttwopartsoflocaledescriptionsasourstandardi18nlocalenames
OnLinuxandSolarissystemsyoucanusethelocale-acommandtogetalistofallsupportedregionalnamesYoucanusethislistasexamplesofsomecommonlocalesForBSDandothersystemsthereisnolocalecommandbuttheregionalinformationisstoredinusrsharelocale
SettingthelocaleNowthatwevedefinedwhatalocaleisweneedtobeabletosetitaccordingtovisitingusersinformation(eitherfromtheirpersonalsettingsthevisiteddomainnameetc)Herearesomemethodswecanusetosettheuserslocale
Fromthedomainname
WecansetauserslocaleviathedomainnameitselfwhentheapplicationusesdifferentdomainsfordifferentregionsForexamplewecanusewwwastacomasourdefaultEnglishwebsiteandthedomainnamewwwastacnasitsChinesecounterpartBysettingupseparatedomainsforseparateregionsyoucandetectandservetherequestedlocaleThistypeofsetuphasseveraladvantages
IdentifyingthelocaleviaURLisdistinctiveandunambiguousUsersintuitivelyknowwhichdomainnamestovisitfortheirspecificregionorlanguageImplementingthisschemeinaGoapplicationisverysimpleandconvenientandcanbeachievedthroughamapConducivetosearchenginecrawlerswhichcanimprovethesitesSEO
Wecanusethefollowingcodetoimplementacorrespondingdomainnamelocale
ifrHost==wwwastacom
i18nSetLocale(en)
elseifrHost==wwwastacn
i18nSetLocale(zh-CN)
elseifrHost==wwwastatw
i18nSetLocale(zh-TW)
Alternativelywecouldhavealsosetlocalesthroughtheuseofsub-domainsuchasenastacomforEnglishsitesandcnastacomforChinesesiteThisschemecanberealizedincodeasfollows
Timezone
230
prefix=stringsSplit(rHost)
ifprefix[0]==en
i18nSetLocale(en)
elseifprefix[0]==cn
i18nSetLocale(zh-CN)
elseifprefix[0]==tw
i18nSetLocale(zh-TW)
Settinglocalesfromthedomainnameaswevedoneabovehasitsadvantageshoweverl10nisgenerallynotimplementedinthiswayFirstofallthecostofdomainnames(althoughusuallyquiteaffordableindividually)canquicklyaddupgiventhateachlocalewillneeditsowndomainnameandoftenthenameofthedomainwillnotnecessarilyfitinwiththelocalcontextSecondlywedontwanttohavetoindividuallyconfigureeachwebsiteforeachlocaleRatherweshouldbeabletodothisprogrammaticallyforinstancebyusingURLparametersLetshavealookatthefollowingdescription
FromURLparameters
Themostcommonwayofimplementingl10nistosetthedesiredlocaledirectlyintheURLparameterssuchwwwastacomhellolocale=zhorwwwastacomzhhelloThiswaywecansettheregionlikesoi18nSetLocale(params[locale])
ThissetuphasalmostalltheadvantagesofprependingthelocaleinfrontofthedomainanditsRESTfulsowedontneedtoaddadditionalmethodstoimplementitThedownsidetothisapproachisthatitrequiresacorrespondinglocaleparameterinsideeachlinkwhichcanbequitecumbersomeandmayincreasecomplexityHoweverwecanwriteagenericfunctionthatproducestheselocale-specificURLssothatalllinksaregeneratedthroughitThisfunctionshouldautomaticallyaddalocaleparametertoeachlinksowhenusersclickthemweareabletoparsetheirrequestswitheaselocale=params[locale]
PerhapswewantourURLstolookevenmoreRESTfulForexamplewecouldmapeachofourresourcesunderaspecificlocalelikewwwastacomenbooksforourEnglishsiteandwwwastacomzhbooksfortheChineseoneThisapproachisnotonlymoreconducivetoURLSEObutisalsomorefriendlyforusersAnybodyvisitingthesiteshouldbeabletoaccesslocale-specificwebsiteresourcesdirectlyfromtheURLSuchURLaddressescanthenbepassedthroughtheapplicationrouterinordertoobtaintheproperlocale(refertotheRESTsectionwhichdescribestherouterplug-inimplementation)
muxGet(localebookslistbook)
Fromtheclientsettingsarea
InsomespecialcaseswerequireexplicitclientinformationinordertosetthelocaleratherthanobtainingitfromtheURLorURLparametersThisinformationmaycomedirectlyfromtheclientsbrowsersettingstheusersIPaddressorthelocationsettingsfilledoutbytheuseratthetimeofregistrationThisapproachismoresuitableforweb-basedapplications
Accept-Language
WhenaclientrequestsinformationusinganHTTPheadersetwiththeAccept-LanguagefieldwecanusethefollowingGocodetoparsetheheaderandsettheappropriateregioncode
AL=rHeaderGet(Accept-Language)
ifAL==en
i18nSetLocale(en)
elseifAL==zh-CN
i18nSetLocale(zh-CN)
elseifAL==zh-TW
i18nSetLocale(zh-TW)
Ofcourseinrealworldapplicationswemayrequiremorerigorousprocessesandrulesforsettinguserregions
Timezone
231
IPAddress
AnotherwayofsettingaclientsregionistolookattheusersIPaddressWecanusethepopularGeoIPGeoLiteCountryorCitylibrariestohelpusrelateuserIPaddressestotheircorrespondingregionalareasImplementingthismechanismisverysimpleweonlyneedtolookuptheusersIPaddressinsideourdatabaseandthenreturnlocale-specificcontentaccordingtowhichregionwasreturned
Userprofile
Youcanalsoletusersprovideyouwiththeirlocaleinformationthroughaninputelementsuchasadrop-downmenu(orsomethingsimilar)WhenwereceivethisinformationwecansaveittotheaccountassociatedwiththeusersprofileWhentheuserlogsinagainwewillbeabletocheckandsettheirlocalesettings-thisguaranteesthateverytimetheuseraccessesthewebsitethereturnedcontentwillbebasedontheirpreviouslysetlocale
SummaryInthissectionwevedemonstratedavarietyofwayswithwhichuserspecificlocalescanbedetectedandsetThesemethodsincludedsettingtheuserlocaleviadomainnamesubdomainnameURLparametersanddirectlyfromclientsettingsBycateringtothespecificneedsofspecificregionswecanprovideacomfortablefamiliarandintuitiveenvironmentforuserstoaccesstheservicesthatweprovide
LinksDirectoryPreviousoneInternationalizationandlocalizationNextsectionLocalizedresources
Timezone
232
102LocalizedResourcesTheprevioussectiondescribedhowtosetlocalesAfterthelocalehasbeensetwethenneedtoaddresstheproblemofstoringtheinformationcorrespondingtospecificlocalesThisinformationcanincludetextualcontenttimeanddatecurrencyvaluespicturesspecificfilesandotherviewresourcesInGoallofthiscontextualinformationisstoredinJSONformatonourbackendtobecalleduponandinjectedintoourviewswhenusersfromspecificregionsvisitourwebsiteForexampleEnglishandChinesecontentwouldbestoredinenjsonandzh-CNjsonfilesrespectively
LocalizedtextualcontentPlaintextisthemostcommonwayofrepresentinginformationinwebapplicationsandthebulkofyourlocalizedcontentwilllikelytakethisformThegoalistoprovidetextualcontentthatisbothidiomatictoregionalexpressionsandfeelsnaturalforforeignusersofyoursiteOnesolutionistocreateanestedmapoflocalesnativelanguagestringsandtheirlocalcounterpartsWhenclientsrequestpageswithsometextualcontentwefirstchecktheirdesiredlocalethenretrievethecorrespondingstringsfromtheappropriatemapThefollowingsnippetisasimpleexampleofthisprocess
packagemain
importfmt
varlocalesmap[string]map[string]string
funcmain()
locales=make(map[string]map[string]string2)
en=make(map[string]string10)
en[pea]=pea
en[bean]=bean
locales[en]=en
cn=make(map[string]string10)
cn[pea]=豌豆
cn[bean]=毛豆
locales[zh-CN]=cn
lang=zh-CN
fmtPrintln(msg(langpea))
fmtPrintln(msg(langbean))
funcmsg(localekeystring)string
ifvok=locales[locale]ok
ifv2ok=v[key]ok
returnv2
return
Theaboveexamplesetsupmapsoftranslatedstringsfordifferentlocales(inthiscasetheChineseandEnglishlocales)WemapourcntranslationstothesameEnglishlanguagekeyssothatwecanreconstructourEnglishtextmessageinChineseIfwewantedtoswitchourtexttoanyotherlocalewemayhaveimplementeditdbeasimplematterofsettingonelangvariable
Simplekey-valuesubstitutionscansometimesbeinadequateforourneedsForexampleifwehadaphrasesuchasIam30yearsoldwhere30isavariablehowwouldwelocalizeitIncaseslikethesewecancombineusethefmtPrintffunctiontoachievethedesiredresult
en[howold]=Iamdyearsold
cn[howold]=我今年d岁了
fmtPrintf(msg(langhowold)30)
Localizedresources
233
TheexamplecodeaboveisonlyforthepurposeofdemonstrationactuallocaledataistypicallystoredinJSONformatinourdatabaseallowingustoexecuteasimplejsonUnmarshaltopopulatemaplocaleswithourstringtranslations
LocalizeddateandtimeBecauseofourtimezoneconventionsthetimeinoneregionoftheworldcanbedifferentthanthetimeinanotherregionSimilarlythewayinwhichtimeisrepresentedcanalsovaryfromlocaletolocaleForexampleaChineseenvironmentmayread2012年10月24日星期三23时11分13秒CSTwhileinEnglishitmightbeWedOct24231113CST2012NotonlyaretherevariationsinlanguagebuttherearedifferencesinformattingalsoSowhenitcomestolocalizingdatesandtimesweneedtoaddressthefollowingtwopoints
1 timezones2 formattingissues
The$GOROOTlibtimepackagetimeinfozipdirectorycontainslocalescorrespondingtotimezonedefinitionsInordertoobtainthetimecorrespondingtoauserscurrentlocaleweshouldfirstusetimeLoadLocation(namestring)togetaLocationobjectcorrespondingtoourlocalepassinginastringrepresentingthelocalesuchasAsiaShanghaiorAmericaChicagoWecanthenusethisLocationobjectinconjunctionwithaTimeobject(obtainedbycallingtimeNow)togetthefinaltimeusingtheTimeobjectsInmethodAdetailedlookatthisprocesscanbeseenbelow(thisexampleusessomeofthevariablesfromtheexampleabove)
en[time_zone]=AmericaChicago
cn[time_zone]=AsiaShanghai
loc_=timeLoadLocation(msg(langtime_zone))
t=timeNow()
t=tIn(loc)
fmtPrintln(tFormat(timeRFC3339))
Wecanhandletextformattinginasimilarwaytosolveourtimeformattingproblem
en[date_format]=Y-m-dHMS
cn[date_format]=Y年m月d日H时M分S秒
fmtPrintln(date(msg(langdate_format)t))
funcdate(fomatstringttimeTime)string
yearmonthday=tDate()
hourminsec=tClock()
ParsingthecorrespondingYmdHMSandthenreturningtheinformation
Yreplacedby2012
mreplacedby10
dreplacedby24
LocalizedcurrencyvalueObviouslycurrencydiffersfromregiontoregionalsoWecantreatitthesamewaywetreatedourdates
en[money]=USDd
cn[money]=¥d元
fmtPrintln(date(msg(langdate_format)100))
funcmoney_format(fomatstringmoneyint64)string
returnfmtSprintf(fomatmoney)
Localizedresources
234
LocalizationofviewsandresourcesWecanservecustomizedviewswithdifferentimagescssjsandotherstaticresourcesdependingonthecurrentlocaleOnewaytoaccomplishthisisbyorganizingthesefilesintotheirrespectivelocalesHeresanexample
views
|--enEnglishTemplates
|--imagesstorepictureinformation
|--jsJSfiles
|--cssCSSfiles
indextplUserHome
logintplLogHome
|--zh-CNChineseTemplates
|--images
|--js
|--css
indextpl
logintpl
Withthisdirectorystructurewecanrenderlocale-specificviewslikeso
s1_=templateParseFiles(views+lang+indextpl)
VVLang=lang
s1Execute(osStdoutVV)
Theresourcesreferencedintheindextplfilecanbedealtwithasfollows
jsfile
ltscripttype=textjavascriptsrc=viewsVVLangjsjqueryjquery-180minjsgtltscriptgt
cssfile
ltlinkhref=viewsVVLangcssbootstrap-responsivemincssrel=stylesheetgt
Picturefiles
ltimgsrc=viewsVVLangimagesbtnpnggt
Withdynamicviewsandthewaywevelocalizedourresourceswewillbeabletoaddmorelocaleswithoutmucheffort
SummaryThissectiondescribedhowtouseandstorelocalresourcesWelearnedthatwecanuseconversionfunctionsandstringinterpolationforthisandsawthatmapscanbeaneffectivewayofstoringlocale-specificdataForthelatterwecouldsimplyextractthecorrespondinglocaleinformationwhenneeded-ifitwastextualcontentwedesiredourmappedtranslationsandidiomscouldbepipeddirectlytotheoutputIfitwassomethingmoresophisticatedliketimeorcurrencywesimplyusedthefmtPrintffunctiontoformatitbefore-handLocalizingourviewsandresourceswastheeasiestcaseandsimplyinvolvedorganizingourfilesintotheirrespectivelocalesthenreferencingthemfromtheirlocalerelativepaths
LinksDirectoryPrevioussectionSettingthedefaultregionNextsectionInternationalsites
Localizedresources
235
103InternationalsitesTheprevioussectionexplainedhowtodealwithlocalizedresourcesnamelybyusinglocaleconfigurationfilesSowhatcanwedoifweneedtodealwithmultiplelocalizedresourcesliketexttranslationstimesanddatesnumbersetcThissectionwilladdresstheseissuesonebyone
ManagingmultiplelocalepackagesInthedevelopmentofanapplicationoftenthefirstthingyouneedtodoistodecidewhetherornotyouwanttosupportmorethanonelanguageIfyoudodecidetosupportmultiplelanguagesyoullneedtodevelopanorganizationalstructuretofacilitatetheprocessofaddingmorelanguagesinthefutureOnewaywecandothisistoputallourrelatedlocalefilestogetherinaconfiglocalesdirectoryorsomethingofthelikeLetssupposeyouwanttosupportbothChineseandEnglishInthiscaseyoudbeplacingboththeenjsonandzhjsonlocalefilesintotheaforementionedfolderTheircontentswouldprobablylooksomethinglikethefollowing
zhjson
zh
submit提交
create创建
enjson
en
submitSubmit
createCreate
Wedecidedtousesome3rdpartyGopackagestohelpusinternationalizeourwebapplicationsInthecaseofgo-i18n(Amoreadvancedi18npackagecanbefoundhere)wefirsthavetoregisterourconfiglocalesdirectorytoloadallofourlocalefiles
Tr=i18nNewLocale()
TrLoadPath(configlocales)
ThispackageissimpletouseWecantestthatitworkslikeso
fmtPrintln(TrTranslate(submit))
Outputsubmit
TrSetLocale(zn)
fmtPrintln(TrTranslate(submit))
Outputs递交
AutomaticallyloadlocalpackageWevejustdescribedhowtoautomaticallyloadcustomlanguagepacksInfactthego-i18nlibrarycomespre-loadedwithabunchofdefaultformattinginformationsuchastimeandcurrencyformatsThesedefaultconfigurationscanbeoverriddenandcustomizedbyuserstosuittheirneedsConsiderthefollowingprocess
Internationalsites
236
Loadthedefaultconfigurationfileswhichareplacedbelowin`go-i18nlocales`
Fileshouldbenamedzhjsonen-jsonen-USjsonetcsowecancontinuouslysupportmorelanguages
func(ilIL)loadDefaultTranslations(dirPathstring)error
direrr=osOpen(dirPath)
iferr=nil
returnerr
deferdirClose()
nameserr=dirReaddirnames(-1)
iferr=nil
returnerr
for_name=rangenames
fullPath=pathJoin(dirPathname)
fierr=osStat(fullPath)
iferr=nil
returnerr
iffiIsDir()
iferr=illoadTranslations(fullPath)err=nil
returnerr
elseiflocale=ilmatchingLocaleFromFileName(name)locale=
fileerr=osOpen(fullPath)
iferr=nil
returnerr
deferfileClose()
iferr=illoadTranslation(filelocale)err=nil
returnerr
returnnil
Usingtheabovecodetoloadallofourdefaulttranslationswecanthenusethefollowingcodetoselectandusealocale
fmtPrintln(TrTime(timeNow()))
Output2009年1月08日星期四203758CST
fmtPrintln(TrTime(timeNow()long))
Output2009年1月08日
fmtPrintln(TrMoney(1111))
Outputyen1111
TemplatemapfuncAbovewevepresentedonewayofmanagingandintegratinganumberoflanguagepacksSomeofthefunctionsweveimplementedarebasedonthelogicallayerforexampleTrTranslateTrTimeTrMoneyandsoonInthelogicallayerwecanusethesefunctions(aftersupplyingtherequiredparameters)forapplyingyourtranslationsoutputtingtheresultsdirectlytothetemplatelayeratrendertimeWhatcanwedoifwewanttousethesefunctionsdirectlyinthetemplatelayerIncaseyouveforgottenearlierinthebookwementionedthatGotemplatessupportcustomtemplatefunctionsThefollowingcodeshowshoweasymapfuncistoimplement
1textinformation
Internationalsites
237
AsimpletextconversionfunctionimplementingamapfunccanbeseenbelowItusesTrTranslatetoperformtheappropriatetranslations
funcI18nT(argsinterface)string
ok=false
varsstring
iflen(args)==1
sok=args[0](string)
ifok
s=fmtSprint(args)
returnTrTranslate(s)
Weregisterthefunctionlikeso
tFuncs(templateFuncMapTI18nT)
Thenuseitfromyourtemplate
VSubmit|T
1 Thedateandtime
DatesandtimescalltheTrTimefunctiontoperformtheirtranslationsThemapfuncisimplementedasfollows
funcI18nTimeDate(argsinterface)string
ok=false
varsstring
iflen(args)==1
sok=args[0](string)
ifok
s=fmtSprint(args)
returnTrTime(s)
Registerthefunctionlikeso
tFuncs(templateFuncMapTDI18nTimeDate)
Thenuseitfromyourtemplate
VNow|TD
3CurrencyInformation
CurrenciesusetheTrMoneyfunctiontoconvertmoneyThemapFuncisimplementedasfollows
Internationalsites
238
funcI18nMoney(argsinterface)string
ok=false
varsstring
iflen(args)==1
sok=args[0](string)
ifok
s=fmtSprint(args)
returnTrMoney(s)
Registerthefunctionlikeso
tFuncs(templateFuncMapMI18nMoney)
Thenuseitfromyourtemplate
VMoney|M
SummaryInthissectionwelearnedhowtoimplementmultiplelanguagepacksinourwebapplicationsWesawthatthroughcustomlanguagepackswecannotonlyeasilyinternationalizeourapplicationsbutfacilitatetheadditionofotherlanguagesalso(throughtheuseofaconfigurationfile)Bydefaultthego-i18npackagewillprovidesomecommonconfigurationsfortimecurrencyetcwhichcanbeveryconvenienttouseWelearnedthatthesefunctionscanalsobeuseddirectlyfromourtemplatesusingmappingfunctionseachtranslatedstringcanbepipeddirectlytoourtemplatesThisenablesourwebapplicationstoaccommodatemultiplelanguageswithminimaleffort
LinksDirectoryPrevioussectionLocalizedresourcesNextsectionSummary
Internationalsites
239
104SummaryThroughthisintroductorychapteroni18nyoushouldnowbefamiliarwithsomeofthestepsandprocessesthatarenecessaryforinternationalizingandlocalizingyourwebsitesIvealsointroducedanopensourcesolutionfori18ninGogo-i18nUsingthisopensourcelibrarywecaneasilyimplementmulti-languageversionsofourwebapplicationsThisallowsourapplicationstobeflexibleandresponsivetolocalaudiencesallaroundtheworldIfyoufindanerrorinthisopensourcelibraryoranymissingfeaturespleaseopenanissueorapullrequestLetsstrivetomakeitoneofGosstandardlibraries
LinksDirectoryPrevioussectionInternationalsitesNextchapterErrorhandlingdebuggingandtesting
Summary
240
11ErrorHandlingDebuggingandTestingWeoftenseethemajorityofaprogrammersprogrammingtimespentoncheckingforbugsandworkingonbugfixesWhetheryouarerefactoringcodeorre-configuringsystemsmuchofyourtimewillundoubtedlybespenttroubleshootingandtestingFromtheoutsidepeoplemaythinkthatallwedoasprogrammersisdesignoursystemsandthenwriteourcodeTheymightthinkthatwehavetheidealjobWedoworkthatisveryengagingandimplementsystemsthathaveneverbeendonebeforeWhilethislastpartmaybetruewhattheydontknowisthatwespendthemajorityofourtimecyclingbetweentroubleshootingdebuggingandtestingourcodeOfcourseifyouhavegoodprogramminghabitsandthetechnologicalsolutionstohelpyoutakeonthesetasksthenyoucanminimizethetimespentdoingthesethingsenablingyoutofocusinsteadonmorevaluablethingsliketheapplicationlogic
UnfortunatelymanyprogrammersarenotthoroughinfulfillingtheirerrorhandlingdebuggingandtestingresponsibilitiesbeforehandInexperiencedprogrammerswilloftenonlymakeanefforttofinderrorsandflawsaftertheyhaveoccurredspendinghourslocatingandfixingproblemsaftertheapplicationisalreadyonlineItsgoodpractice(andprobablycommonsense)thatweshoulddesignourapplicationswithpropererrorhandlingtestcasesetcfromthegetgoThiswillmakeyourjobandthejobsofalltheotherdeveloperswhomaybeworkingonyourapplicationsomedaymucheasierwhentheyinevitablyneedtomodifythecodeorupgradethesystem
IntheprocessofdevelopingwebapplicationsyouwillinevitablyencounterunforeseenerrorsWhatsthemostefficientwayoffindingthecausesoftheseerrorsandsolvingthemSection111describeshowtohandleerrorsintheGolanguageaswellashowtodesignyourownerrorhandlingpackageandfunctionsSection112describeshowtouseGDBtodebugprogramsunderdynamicoperatingconditionsdependingonavarietyofvariableinformationWethendiscussapplicationmonitoringanddebuggingoperations
Section113willexplainunittestinginGoandfeaturesomein-depthdiscussionsandexamplesonhowtowriteunittestsaswellasdefiningGosunittestingrulesWellseehowfollowingtheseruleswillensurethatwhenupgradingormodifyingyourapplicationthetestcodewillbeabletorunsmoothly
ManyprogrammersavoidspendingtimetolearnandcultivategooddebuggingandtestinghabitsThischaptertakesontheseissueshead-onsoyouwonthavetorunawayfromthesetasksanylongerSinceyourejustlearninghowtobuildwebapplicationsinGoletsusethisopportunitytoestablishthesegoodhabitsfromtheverybeginning
LinksDirectoryPreviouschapterChapter10summaryNextsectionErrorhandling
Errorhandlingdebuggingandtesting
241
111ErrorhandlingGosmajordesignconsiderationsarerootedinthefollowingideasasimpleclearandconcisesyntax(similartoC)andstatementswhichareexplicitanddontcontainanyhiddenorunexpectedthingsGoserrorhandlingschemereflectsalloftheseprinciplesinthewaythatitsimplementedIfyourefamiliarwiththeClanguageyoullknowthatitscommontoreturn-1orNULLvaluestoindicatethatanerrorhasoccurredHoweveruserswhoarenotfamiliarwithCsAPIwillnotknowexactlywhatthesereturnvaluesmeanInCitsnotexplicitwhetheravalueof0indicatessuccessoffailureOntheotherhandGoexplicitlydefinesatypecallederrorforthesolepurposeofexpressingerrorsWheneverafunctionreturnswechecktoseewhethertheerrorvariableisnilornottodetermineiftheoperationwassuccessfulForexampletheosOpenfunctionfailsitwillreturnanon-nilerrorvariable
funcOpen(namestring)(fileFileerrerror)
HeresanexampleofhowwedhandleanerrorinosOpenFirstweattempttoopenafileWhenthefunctionreturnswechecktoseewhetheritsucceededornotbycomparingtheerrorreturnvaluewithnilcallinglogFataltooutputanerrormessageifitsanon-nilvalue
ferr=osOpen(filenameext)
iferr=nil
logFatal(err)
SimilartotheosOpenfunctionthefunctionsinGosstandardpackagesallreturnerrorvariablestofacilitateerrorhandlingThissectionwillgointodetailaboutthedesignoferrortypesanddiscusshowtoproperlyhandleerrorsinwebapplications
Errortypeerrorisaninterfacetypewiththefollowingdefinition
typeerrorinterface
Error()string
errorisabuilt-ininterfacetypeWecanfinditsdefinitioninthebuiltinpackagebelowWealsohavealotofinternalpackageswhichuseerrorinaprivatestructurecallederrorStringwhichimplementstheerrorinterface
errorStringisatrivialimplementationoferror
typeerrorStringstruct
sstring
func(eerrorString)Error()string
returnes
YoucanconvertaregularstringtoanerrorStringthrougherrorsNewinordertogetanobjectthatsatisfiestheerrorinterfaceItsinternalimplementationisasfollows
Newreturnsanerrorthatformatsasthegiventext
funcNew(textstring)error
returnamperrorStringtext
Errorhandling
242
ThefollowingexampledemonstrateshowtouseerrorsNew
funcSqrt(ffloat64)(float64error)
ifflt0
return0errorsNew(mathsquarerootofnegativenumber)
implementation
InthefollowingexamplewepassanegativenumbertoourSqrtfunctionCheckingtheerrvariablewecheckwhethertheerrorobjectisnon-nilusingasimplenilcomparisonTheresultofthecomparisonistruesofmtPrintln(thefmtpackagecallstheerrormethodwhendealingwitherrorcalls)iscalledtooutputanerror
ferr=Sqrt(-1)
iferr=nil
fmtPrintln(err)
CustomErrorsThroughtheabovedescriptionweknowthatagoErrorisaninterfaceBydefiningastructthatimplementsthisinterfacewecanimplementtheirerrordefinitionsHeresanexamplefromtheJSONpackage
typeSyntaxErrorstruct
msgstringerrordescription
Offsetint64wheretheerroroccurred
func(eSyntaxError)Error()stringreturnemsg
TheerrorsOffsetfieldwillnotbeprintedatruntimewhensyntaxerrorsoccurbutusingatypeassertionerrortypeyoucanprintthedesirederrormessage
iferr=decDecode(ampval)err=nil
ifserrok=err(jsonSyntaxError)ok
linecol=findLine(fserrOffset)
returnfmtErrorf(sddvfName()linecolerr)
returnerr
ItshouldbenotedthatwhenthefunctionreturnsacustomerrorthereturnvalueissettotherecommendedtypeoferrorratherthanacustomerrortypeBecarefulnottopre-declarevariablesofcustomerrortypesForexample
funcDecode()SyntaxError
errorwhichmayleadtothecallerserr=nilcomparisontoalwaysbetrue
varerrSyntaxErrorpre-declareerrorvariable
ifanerrorcondition
err=ampSyntaxError
returnerrerrorerralwaysequalnon-nilcausescallerserr=nilcomparisontoalwaysbetrue
Seehttpgolangorgdocfaqnil_errorforanindepthexplanation
TheaboveexampleshowshowtoimplementasimplecustomErrortypeButwhatifweneedmoresophisticatederrorhandlingInthiscasewehavetorefertothenetpackageapproach
Errorhandling
243
packagenet
typeErrorinterface
error
Timeout()boolIstheerroratimeout
Temporary()boolIstheerrortemporary
UsingtypeassertionwecancheckwhetherornotourerrorisoftypenetErrorasshowninthefollowingexampleThisallowsustorefineourerrorhandling-ifatemporaryerroroccursonthenetworkitwillsleepfor1secondthenretrytheoperation
ifnerrok=err(netError)okampampnerrTemporary()
timeSleep(1e9)
continue
iferr=nil
logFatal(err)
ErrorhandlingGohandleserrorsandchecksthereturnvaluesoffunctionsinaC-likefashionwhichisdifferenttohowmostoftheothermajorlanguagesdoThismakesthecodemoreexplicitandpredictablebutalsomoreverboseToreducetheredundancyofourerror-handlingcodewecanuseabstracterrorhandlingfunctionsthatallowustoimplementsimilarerrorhandlingbehaviour
funcinit()
httpHandleFunc(viewviewRecord)
funcviewRecord(whttpResponseWriterrhttpRequest)
c=appengineNewContext(r)
key=datastoreNewKey(cRecordrFormValue(id)0nil)
record=new(Record)
iferr=datastoreGet(ckeyrecord)err=nil
httpError(werrError()500)
return
iferr=viewTemplateExecute(wrecord)err=nil
httpError(werrError()500)
TheaboveexampledemonstratehowthedataaccessandtemplatecallhasdetectedanerrorWhenanerroroccursacalltounifiedhandlerhttpErrorreturnsa500errorcodetotheclientanddisplaysthecorrespondingerrordataButwhenmoreandmoreHandleFunccallsaremadesoerror-handlinglogiccodewillincreaseWecancustomizetheroutertoreducecode(refertothethirdchapterofHTTPformoredetail)
typeappHandlerfunc(httpResponseWriterhttpRequest)error
func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)
iferr=fn(wr)err=nil
httpError(werrError()500)
AbovewevedefinedacustomrouterWecanthenregisterourhandlerasusual
Errorhandling
244
funcinit()
httpHandle(viewappHandler(viewRecord))
Theviewhandlercanthenbehandledbythefollowingcodeitisalotsimplerthanouroriginalimplementationisntit
funcviewRecord(whttpResponseWriterrhttpRequest)error
c=appengineNewContext(r)
key=datastoreNewKey(cRecordrFormValue(id)0nil)
record=new(Record)
iferr=datastoreGet(ckeyrecord)err=nil
returnerr
returnviewTemplateExecute(wrecord)
Theerrorhandlerexampleabovewillreturnthe500InternalErrorcodetouserswhenanyerrorsoccurinadditiontoprintingoutthecorrespondingerrorcodeInfactwecancustomizethetypeoferrorreturnedtooutputamoredeveloperfriendlyerrormessagewithinformationthatisusefulfordebugginglikeso
typeappErrorstruct
Errorerror
Messagestring
Codeint
Ourcustomroutercanbechangedaccordingly
typeappHandlerfunc(httpResponseWriterhttpRequest)appError
func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)
ife=fn(wr)e=nileisappErrornotosError
c=appengineNewContext(r)
cErrorf(veError)
httpError(weMessageeCode)
Afterwevefinishedmodifyingourcustomerrorourlogiccanbechangedasfollows
funcviewRecord(whttpResponseWriterrhttpRequest)appError
c=appengineNewContext(r)
key=datastoreNewKey(cRecordrFormValue(id)0nil)
record=new(Record)
iferr=datastoreGet(ckeyrecord)err=nil
returnampappErrorerrRecordnotfound404
iferr=viewTemplateExecute(wrecord)err=nil
returnampappErrorerrCantdisplayrecord500
returnnil
AsshownabovewecanreturndifferenterrorcodesanderrormessagesinourviewsdependingonthesituationAlthoughthisversionofourcodefunctionssimilarlytothepreviousversionitsmoreexplicitanditserrormessagepromptsaremorecomprehensibleAllofthesefactorscanhelptomakeyourapplicationmorescalableascomplexityincreases
Summary
Errorhandling
245
FaulttoleranceisaveryimportantaspectofanyprogramminglanguageInGoitisachievedthrougherrorhandlingAlthoughErrorisonlyoneinterfaceitcanhavemanyvariationsinthewaythatitsimplementedandwecancustomizeitaccordingtoourneedsonacasebycasebasisByintroducingthesevariouserrorhandlingconceptswehopethatyouwillhavegainedsomeinsightonhowtoimplementbettererrorhandlingschemesinyourownwebapplications
LinksDirectoryPrevioussectionErrorhandlingdebuggingandtestingNextsectionDebuggingbyusingGDB
Errorhandling
246
112DebuggingwithGDBDuringthedevelopmentprocessofanyapplicationdeveloperswillalwaysneedtoperformsomekindofcodedebuggingPHPPythonandmostoftheotherdynamiclanguagesareabletobemodifiedatruntimeaslongasthemodificationsdonotexplicitlyneedtobecompiledWecaneasilyprintdataindynamicoperatingenvironmentsoutputtingourchangesandprintingvariableinformationdirectlyInGoyoucanofcoursespeckleyourcodewithPrintlnsbefore-handtodisplayvariableinformationfordebuggingpurposesbutanychangestoyourcodeneedtoberecompiledeverytimeThiscanquicklybecomecumbersomeIfyouveprogrammedinPythonorJavascriptyoullknowthattheformerprovidestoolssuchaspdbandipdbfordebuggingandthelatterhassimilartoolsthatareabletodynamicallydisplayvariableinformationandfacilitatesingle-stepdebuggingFortunatelyGohasnativesupportforasimilartoolwhichprovidessuchdebuggingfeaturesGDBThissectionservesasabriefintroductionintodebuggingGoapplicationsusingGDB
GDBdebuggingprofileGDBisapowerfuldebuggingtooltargetingUNIX-likesystemsreleasedbytheFSF(FreeSoftwareFoundation)GDBallowsustodothefollowingthings
1 Initialsettingscanbecustomizeaccordingtothespecificrequirementsofyourapplication2 Canbesetsothattheprogrambeingdebuggedinthedevelopersconsolestopsattheprescribedbreakpoints
(breakpointscanbeconditionalexpressions)3 Whentheprogramhasbeenstoppedyoucancheckitscurrentstatetoseewhathappened4 Dynamicallychangethecurrentprogramsexecutionenvironment
TodebugyourGoapplicationsusingGDBtheversionofGDByouusemustbegreaterthan71
WhencompilingGoprogramsthefollowingpointsrequireparticularattention
1 Using-ldflags-swillpreventthestandarddebugginginformationfrombeingprinted2 Using-gcflags-N-lwillpreventGofromperformingsomeofitsautomatedoptimizations-optimizationsof
aggregatevariablesfunctionsetcTheseoptimizationscanmakeitverydifficultforGDBtodoitsjobsoitsbesttodisablethematcompiletimeusingtheseflags
SomeofGDBsmostcommonlyusedcommandsareasfollows
list
AlsousedinitsabbreviatedformllistisusedtodisplaythesourcecodeBydefaultitdisplaystenlinesofcodeandyoucanspecifythelineyouwishtodisplayForexamplethecommandlist15displaystenlinesofcodecenteredaroundline15asshownbelow
10timeSleep(2timeSecond)
11clt-i
12
13close(c)
14
15
16funcmain()
17msg=Startingmain
18fmtPrintln(msg)
19bus=make(chanint)
break
AlsousedinitsabbreviatedformbbreakisusedtosetbreakpointsandtakesasanargumentthatdefineswhichpointtosetthebreakpointatForexampleb10setsabreakpointatthetenthrow
delete
DebuggingbyusingGDB
247
AlsousedinitsabbreviatedformddeleteisusedtodeletebreakpointsThebreakpointissetfollowedbytheserialnumberTheserialnumbercanbeobtainedthroughtheinfobreakpointscommandBreakpointssetwiththeircorrespondingserialnumbersaredisplayedasfollowstosetabreakpointnumber
NumTypeDispEnbAddressWhat
2breakpointkeepy0x0000000000400dc3inmainmainathomexiemengjungdbgo23
breakpointalreadyhit1time
backtrace
Abbreviatedasbtthiscommandisusedtoprinttheexecutionofthecodeforinstance
0mainmain()athomexiemengjungdbgo23
10x000000000040d61einruntimemain()athomexiemengjungosrcpkgruntimeprocc244
20x000000000040d6c1inschedunlock()athomexiemengjungosrcpkgruntimeprocc267
30x0000000000000000in()
info
TheinfocommandcanbeusedinconjunctionwithseveralparameterstodisplayinformationThefollowingparametersarecommonlyused
infolocals
Displaysthecurrentlyexecutingprogramsvariablevalues
infobreakpoints
Displaysalistofcurrentlysetbreakpoints
infogoroutines
Displaysthecurrentlistofrunninggoroutinesasshowninthefollowingcodewiththeindicatingthecurrentexecution
1runningruntimegosched
2syscallruntimeentersyscall
3waitingruntimegosched
4runnableruntimegosched
AbbreviatedaspthiscommandisusedtoprintvariablesorotherinformationIttakesasargumentsthevariablenamestobeprintedandofcoursetherearesomeveryusefulfunctionssuchas$len()and$cap()thatcanbeusedtoreturnthelengthorcapacityofthecurrentstringsslicesormaps
whatis
whatisisusedtodisplaythecurrentvariabletypefollowedbythevariablenameForinstancewhatismsgwilloutputthefollowing
type=structstring
next
Abbreviatedasnnextisusedinsingle-stepdebuggingtoskiptothenextstepWhenthereisabreakpointyoucanenterntojumptothenextsteptocontinue
continue
AbbreviatedasccontinueisusedtojumpoutofthecurrentbreakpointandcanbefollowedbyaparameterNwhichspecifiesthenumberoftimestoskipthebreakpoint
setvariable
DebuggingbyusingGDB
248
ThiscommandisusedtochangethevalueofavariableintheprocessItcanbeusedlikesosetvariableltvargt=ltvaluegt
ThedebuggingprocessNowletstakealookatthefollowingcodetoseehowGDBistypicallyusedtodebugGoprograms
packagemain
import(
fmt
time
)
funccounting(cchanlt-int)
fori=0ilt10i++
timeSleep(2timeSecond)
clt-i
close(c)
funcmain()
msg=Startingmain
fmtPrintln(msg)
bus=make(chanint)
msg=startingagofunc
gocounting(bus)
forcount=rangebus
fmtPrintln(countcount)
Nowwecompilethefilecreatinganexecutablefilecalledgdbfile
gobuild-gcflags-N-lgdbfilego
UsetheGDBcommandtostartdebugging
gdbgdbfile
AfterfirststartingGDByoullhavetoentertheruncommandtoseeyourprogramrunningYouwillthenseetheprogramoutputthefollowingexecutingtheprogramdirectlyfromthecommandlinewilloutputexactlythesamething
(gdb)run
Startingprogramhomexiemengjungdbfile
Startingmain
count0
count1
count2
count3
count4
count5
count6
count7
count8
count9
[LWP2771exited]
[Inferior1(process2771)exitednormally]
Oknowthatweknowhowtogettheprogramupandrunningletstakealookatsettingbreakpoints
DebuggingbyusingGDB
249