293

golang book

Embed Size (px)

Citation preview

  • 1. Introduction2. GoEnvironmentConfiguration

    i. Installationii. $GOPATHandworkspaceiii. Gocommandsiv. Godevelopmenttoolsv. Summary

    3. Gobasicknowledgei. Hello,Goii. Gofoundationiii. Controlstatementsandfunctionsiv. structv. Object-orientedvi. interfacevii. Concurrencyviii. Summary

    4. Webfoundationi. Webworkingprinciplesii. Buildasimplewebserveriii. HowGoworkswithwebiv. Getintohttppackagev. Summary

    5. HTTPFormi. Processforminputsii. Validationofinputsiii. Crosssitescriptingiv. Duplicatesubmissionsv. Fileuploadvi. Summary

    6. Databasei. database/sqlinterfaceii. HowtouseMySQLiii. HowtouseSQLiteiv. HowtousePostgreSQLv. HowtousebeedbORMvi. NOSQLvii. Summary

    7. Datastorageandsessioni. Sessionandcookiesii. HowtousesessioninGoiii. Sessionstorageiv. Preventhijackofsessionv. Summary

    8. Textfilesi. XMLii. JSONiii. Regexpiv. Templatesv. Filesvi. Stringsvii. Summary

    9. Webservices

    TableofContents

  • i. Socketsii. WebSocketiii. RESTiv. RPCv. Summary

    10. Securityandencryptioni. CSRFattacksii. Filterinputsiii. XSSattacksiv. SQLinjectionv. Passwordstoragevi. Encryptanddecryptdatavii. Summary

    11. Internationalizationandlocalizationi. Timezoneii. Localizedresourcesiii. Internationalsitesiv. Summary

    12. Errorhandling,debuggingandtestingi. Errorhandlingii. DebuggingbyusingGDBiii. Writetestcasesiv. Summary

    13. Deploymentandmaintenancei. Logsii. Errorsandcrashesiii. Deploymentiv. Backupandrecoveryv. Summary

    14. Buildawebframeworki. Projectprogramii. Customizedroutersiii. Designcontrollersiv. Logsandconfigurationsv. Add,deleteandupdateblogsvi. Summary

    15. Developwebframeworki. Staticfilesii. Sessioniii. Formiv. Uservalidationv. Multi-languagesupportvi. pprofvii. Summary

    16. References17. preface

  • BecauseI'minterestedinwebapplicationdevelopment,Iusedmyfreetimetowritethisbookasanopensourceversion.Itdoesn'tmeanthatIhaveaverygoodabilitytobuildwebapplications;IwouldliketosharewhatI'vedonewithGoinbuildingwebapplications.

    ForthoseofyouwhoareworkingwithPHP/Python/Ruby,youwilllearnhowtobuildawebapplicationwithGo.ForthoseofyouwhoareworkingwithC/C++,youwillknowhowthewebworks.

    Ibelievethepurposeofstudyingissharingwithothers.ThehappiestthinginmylifeissharingeverythingI'veknownwithmorepeople.

    AliPay:

    alipay

    EnglishDonate:donate

    QQ386056972

    BBShttp://golanghome.com/

    AprilCitizen(reviewcode)HongRuiqi(reviewcode)BianJiang(writetheconfigurationsaboutVimandEmacsforGodevelopment)OlingCat(reviewcode)WenleiWu(providesomepictures)Polaris(reviewwholebook)RainTrail(reviewchapter2and3)

    ThisbookislicensedundertheCCBY-SA3.0License,thecodeislicensedunderaBSD3-ClauseLicense,unlessotherwisespecified.

    BuildWebApplicationwithGolang

    Purpose

    Donate

    Community

    Acknowledgments

    License

  • WelcometotheworldofGo,let'sstartexploring!

    Goisafast-compiled,garbage-collected,concurrentsystemsprogramminglanguage.Ithasthefollowingadvantages:

    Compilesalargeprojectwithinafewseconds.Providesasoftwaredevelopmentmodelthatiseasytoreasonabout,avoidingmostoftheproblemsassociatedwithC-styleheaderfiles.Isastaticlanguagethatdoesnothavelevelsinitstypesystem,sousersdonotneedtospendmuchtimedealingwithrelationsbetweentypes.Itismorelikealightweightobject-orientedlanguage.Performsgarbagecollection.Itprovidesbasicsupportforconcurrencyandcommunication.Designedformulti-corecomputers.

    Goisacompiledlanguage.Itcombinesthedevelopmentefficiencyofinterpretedordynamiclanguageswiththesecurityofstaticlanguages.Itisgoingtobethelanguageofchoiceformodern,multi-corecomputerswithnetworking.Forthesepurposes,therearesomeproblemsthatneedtoinherentlyberesolvedatthelevelofthelanguageofchoice,suchasarichlyexpressivelightweighttypesystem,anativeconcurrencymodel,andstrictlyregulatedgarbagecollection.Forquitesometime,nopackagesortoolshaveemergedthathaveaimedtosolvealloftheseproblemsinapragmaticfashion;thuswasbornthemotivationfortheGolanguage.

    Inthischapter,IwillshowyouhowtoinstallandconfigureyourownGodevelopmentenvironment.

    DirectoryNextsection:Installation

    1GoEnvironmentConfiguration

    Links

  • TherearemanywaystoconfiguretheGodevelopmentenvironmentonyourcomputer,andyoucanchoosewhicheveroneyoulike.Thethreemostcommonwaysareasfollows.

    Officialinstallationpackages.TheGoteamprovidesconvenientinstallationpackagesinWindows,Linux,Macandotheroperatingsystems.Thisisprobablytheeasiestwaytogetstarted.

    Installityourselffromsourcecode.PopularwithdeveloperswhoarefamiliarwithUnix-likesystems.

    Usingthird-partytools.Therearemanythird-partytoolsandpackagemanagersforinstallingGo,likeapt-getinUbuntuandhomebrewforMac.

    IncaseyouwanttoinstallmorethanoneversionofGoonacomputer,youshouldtakealookatatoolcalledGVM.ItisthebesttoolI'veseensofarforaccomplishingthistask,otherwiseyou'dhavetodealwithityourself.

    BecausesomepartsofGoarewritteninPlan9CandAT&Tassembler,youhavetoinstallaCcompilerbeforetakingthenextstep.

    OnaMac,ifyouhaveinstalledXcode,youalreadyhavethecompiler.

    OnUnix-likesystems,youneedtoinstallgccorasimilarcompiler.Forexample,usingthepackagemanagerapt-get(includedwithUbuntu),onecaninstalltherequiredcompilersasfollows:

    sudoapt-getinstallgcclibc6-dev

    OnWindows,youneedtoinstallMinGWinordertoinstallgcc.Don'tforgettoconfigureyourenvironmentvariablesaftertheinstallationhascompleted.(Everythingthatlookslikethismeansit'scommentedbyatranslator:Ifyouareusing64-bitWindows,youshouldinstallthe64-bitversionofMinGW)

    TheGoteamusesMercurialtomanagetheirsourcecode,soyouneedtoinstallthistoolinordertodownloadtheGosourcecode.

    Atthispoint,executethefollowingcommandstoclonetheGosourcecodeandcompileit.(Itwillclonethesourcecodetoyourcurrentdirectory.Switchyourworkpathbeforeyoucontinue.Thismaytakesometime.)

    hgclone-ureleasehttps://code.google.com/p/gocdgo/src./all.bash

    Asuccessfulinstallationwillendwiththemessage"ALLTESTSPASSED."

    OnWindows,youcanachievethesamebyrunningall.bat.

    IfyouareusingWindows,theinstallationpackagewillsetyourenvironmentvariablesautomatically.InUnix-likesystems,youneedtosetthesevariablesmanuallyasfollows.(IfyourGoversionisgreaterthan1.0,youdon'thavetoset$GOBIN,anditwillautomaticallyberelatedtoyour$GOROOT/bin,whichwewilltalkaboutinthenextsection)

    1.1Installation

    ThreewaystoinstallGo

    Installfromsourcecode

  • exportGOROOT=$HOME/goexportGOBIN=$GOROOT/binexportPATH=$PATH:$GOROOT/bin

    Ifyouseethefollowinginformationonyourscreen,you'reallset.

    Figure1.1Informationafterinstallingfromsourcecode

    OnceyouseetheusageinformationofGo,itmeansyouhavesuccessfullyinstalledGoonyourcomputer.Ifitsays"nosuchcommand",checkthatyour$PATHenvironmentvariablecontainstheinstallationpathofGo.

    Gohasone-clickinstallationpackagesforeverysupportedoperatingsystem.ThesepackageswillinstallGoin/usr/local/go(c:\GoinWindows)bydefault.Ofcoursethiscanbemodified,butyoualsoneedtochangealltheenvironmentvariablesmanuallyasI'veshownabove.

    Ournextstepdependsonyouroperatingsystemtype,sowehavetocheckitbeforewedownloadthestandardinstallationpackages.

    IfyouareusingWindows,pressWin+Randthenrunthecommandtool.Typethesysteminfocommandanditwillshowyousomeusefulsysteminformation.Findthelinethatsays"systemtype"-ifyousee"x64-basedPC"thatmeansyouroperatingsystemis64-bit,32-bitotherwise.

    Istronglyrecommenddownloadingthe64-bitpackageifyouareaMacuser,asGonolongersupportspure32-bitprocessorsonMacOSX.

    Linuxuserscantypeuname-aintheterminaltoseesysteminformation.A64-bitoperatingsystemwillshowthefollowing:

    x86_64x86_64x86_64GNU/Linux//somemachinessuchasUbuntu10.04willshowasfollowingx86_64GNU/Linux

    32-bitoperatingsystemsinsteadshow:

    i686i686i386GNU/Linux

    Gotothedownloadpage,choosego1.0.3.darwin-386.pkgfor32-bitsystemsandgo1.0.3.darwin-amd64.pkgfor64-bitsystems.Goingallthewaytotheendbyclicking"next",~/go/binwillbeaddedtoyoursystem's$PATHafteryoufinishtheinstallation.Nowopentheterminalandtypego.Youshouldseethesameoutputshowninigure1.1.

    Gotothedownloadpage,choosego1.0.3.linux-386.tar.gzfor32-bitsystemsandgo1.0.3.linux-amd64.tar.gzfor64-bitsystems.SupposeyouwanttoinstallGointhe$GO_INSTALL_DIRpath.Uncompressthetar.gztoyourchosenpathusingthecommandtarzxvfgo1.0.3.linux-amd64.tar.gz-C$GO_INSTALL_DIR.Thensetyour$PATHwiththefollowing:exportPATH=$PATH:$GO_INSTALL_DIR/go/bin.Nowjustopentheterminalandtypego.Youshouldnowseethesameoutputdisplayedinfigure1.1.

    Usingthestandardinstallationpackages

    Howtocheckifyouroperatingsystemis32-bitor64-bit?

    Mac

    Linux

  • Gotothedownloadpage,choosego1.0.3.windows-386.msifor32-bitsystemsandgo1.0.3.windows-amd64.msifor64-bitsystems.Goingallthewaytotheendbyclicking"next",c:/go/binwillbeaddedtopath.Nowjustopenacommandlinewindowandtypego.Youshouldnowseethesameoutputdisplayedinfigure1.1.

    GVMisaGomulti-versioncontroltooldevelopedbyathird-party,likervmforruby.It'squiteeasytouse.Installgvmbytypingthefollowingcommandsinyourterminal:

    bash10{fmt.Println("xisgreaterthan10")}else{fmt.Println("xislessthan10")}

    ThemostusefulthingconcerningifinGoisthatitcanhaveoneinitializationstatementbeforetheconditionalstatement.Thescopeofthevariablesdefinedinthisinitializationstatementareonlyavailableinsidetheblockofthedefiningif.

    //initializex,thencheckifxgreaterthanifx:=computedValue();x>10{fmt.Println("xisgreaterthan10")}else{fmt.Println("xislessthan10")}

    //thefollowingcodewillnotcompilefmt.Println(x)

    Useif-elseformultipleconditions.

    ifinteger==3{fmt.Println("Theintegerisequalto3")}elseifintegerp2.age{returnp1,p1.age-p2.age}returnp2,p2.age-p1.age}

    funcmain(){vartomperson

    //initializationtom.name,tom.age="Tom",18

    //initializetwovaluesbyformat"field:value"bob:=person{age:25,name:"Bob"}

    //initializetwovalueswithorderpaul:=person{"Paul",43}

    tb_Older,tb_diff:=Older(tom,bob)tp_Older,tp_diff:=Older(tom,paul)bp_Older,bp_diff:=Older(bob,paul)

    fmt.Printf("Of%sand%s,%sisolderby%dyears\n",tom.name,bob.name,tb_Older.name,tb_diff)

    fmt.Printf("Of%sand%s,%sisolderby%dyears\n",tom.name,paul.name,tp_Older.name,tp_diff)

    fmt.Printf("Of%sand%s,%sisolderby%dyears\n",bob.name,paul.name,bp_Older.name,bp_diff)}

    I'vejustintroducedtoyouhowtodefineastructwithfieldnamesandtype.Infact,Gosupportsfieldswithoutnames,butwithtypes.Wecalltheseembeddedfields.

    Whentheembeddedfieldisastruct,allthefieldsinthatstructwillimplicitlybethefieldsinthestructinwhichithasbeenembdedded.

    Let'sseeoneexample.

    packagemainimport"fmt"

    typeHumanstruct{namestringageintweightint}

    typeStudentstruct{Human//embeddedfield,itmeansStudentstructincludesallfieldsthatHumanhas.specialitystring}

    funcmain(){//initializeastudentmark:=Student{Human{"Mark",25,120},"ComputerScience"}

    //accessfieldsfmt.Println("Hisnameis",mark.name)fmt.Println("Hisageis",mark.age)fmt.Println("Hisweightis",mark.weight)fmt.Println("Hisspecialityis",mark.speciality)//modifynotesmark.speciality="AI"fmt.Println("Markchangedhisspeciality")fmt.Println("Hisspecialityis",mark.speciality)//modifyage

    embeddedfieldsinstruct

  • fmt.Println("Markbecomeold")mark.age=46fmt.Println("Hisageis",mark.age)//modifyweightfmt.Println("Markisnotanathletanymore")mark.weight+=60fmt.Println("Hisweightis",mark.weight)}

    Figure2.7InheritanceinStudentandHuman

    WeseethatwecanaccesstheageandnamefieldsinStudentjustlikewecaninHuman.Thisishowembeddedfieldswork.It'sverycool,isn'tit?Holdon,there'ssomethingcooler!YoucanevenuseStudenttoaccessHumaninthisembeddedfield!

    mark.Human=Human{"Marcus",55,220}mark.Human.age-=1

    AllthetypesinGocanbeusedasembeddedfields.

    packagemainimport"fmt"

    typeSkills[]string

    typeHumanstruct{namestringageintweightint}

    typeStudentstruct{Human//structasembeddedfieldSkills//stringsliceasembeddedfieldint//built-intypeasembeddedfieldspecialitystring}

    funcmain(){//initializeStudentJanejane:=Student{Human:Human{"Jane",35,100},speciality:"Biology"}//accessfieldsfmt.Println("Hernameis",jane.name)fmt.Println("Herageis",jane.age)fmt.Println("Herweightis",jane.weight)fmt.Println("Herspecialityis",jane.speciality)//modifyvalueofskillfieldjane.Skills=[]string{"anatomy"}fmt.Println("Herskillsare",jane.Skills)fmt.Println("Sheacquiredtwonewones")jane.Skills=append(jane.Skills,"physics","golang")fmt.Println("Herskillsnoware",jane.Skills)//modifyembeddedfieldjane.int=3fmt.Println("Herpreferrednumberis",jane.int)}

    Intheaboveexample,wecanseethatalltypescanbeembeddedfieldsandwecanusefunctionstooperateonthem.

    Thereisonemoreproblemhowever.IfHumanhasafieldcalledphoneandStudenthasafieldwithsamename,whatshouldwedo?

    Gouseaverysimplewaytosolveit.Theouterfieldsgetupperaccesslevels,whichmeanswhenyouaccessstudent.phone,wewillgetthefieldcalledphoneinstudent,nottheoneintheHumanstruct.Thisfeaturecanbesimplyseenasfieldoverloading.

  • packagemainimport"fmt"

    typeHumanstruct{namestringageintphonestring//Humanhasphonefield}

    typeEmployeestruct{Human//embeddedfieldHumanspecialitystringphonestring//phoneinemployee}

    funcmain(){Bob:=Employee{Human{"Bob",34,"777-444-XXXX"},"Designer","333-222"}fmt.Println("Bob'sworkphoneis:",Bob.phone)//accessphonefieldinHumanfmt.Println("Bob'spersonalphoneis:",Bob.Human.phone)}

    DirectoryPrevioussection:ControlstatementsandfunctionsNextsection:Object-oriented

    Links

  • Wetalkedaboutfunctionsandstructsinthelasttwosections,butdidyoueverconsiderusingfunctionsasfieldsofastruct?Inthissection,Iwillintroduceyoutoanotherformofmethodthathasareceiver,whichiscalledmethod.

    Supposeyoudefinea"rectangle"structandyouwanttocalculateitsarea.We'dtypicallyusethefollowingcodetoachievethisgoal.

    packagemainimport"fmt"

    typeRectanglestruct{width,heightfloat64}

    funcarea(rRectangle)float64{returnr.width*r.height}

    funcmain(){r1:=Rectangle{12,2}r2:=Rectangle{9,4}fmt.Println("Areaofr1is:",area(r1))fmt.Println("Areaofr2is:",area(r2))}

    Theaboveexamplecancalculatearectangle'sarea.Weusethefunctioncalledarea,butit'snotamethodoftherectanglestruct(likeclassmethodsinclassicobject-orientedlanguages).Thefunctionandstructaretwoindependentthingsasyoumaynotice.

    It'snotaproblemsofar.However,ifyoualsohavetocalculatetheareaofacircle,square,pentagon,oranyotherkindofshape,youaregoingtoneedtoaddadditionalfunctionswithverysimilarnames.

    Figure2.8Relationshipbetweenfunctionandstruct

    Obviouslythat'snotcool.Also,theareashouldreallybethepropertyofacircleorrectangle.

    Forthosereasons,wehavethemethodconcept.methodisaffiliatedwithtype.Ithasthesamesyntaxasfunctionsdoexceptforanadditionalparameterafterthefunckeywordcalledthereceiver,whichisthemainbodyofthatmethod.

    Usingthesameexample,Rectangle.area()belongsdirectlytorectangle,insteadofasaperipheralfunction.Morespecifically,length,widthandarea()allbelongtorectangle.

    AsRobPikesaid.

    "Amethodisafunctionwithanimplicitfirstargument,calledareceiver."

    Syntaxofmethod.

    func(rReceiverType)funcName(parameters)(results)

    Let'schangeourexampleusingmethodinstead.

    Object-oriented

    method

  • packagemainimport("fmt""math")

    typeRectanglestruct{width,heightfloat64}

    typeCirclestruct{radiusfloat64}

    func(rRectangle)area()float64{returnr.width*r.height}

    func(cCircle)area()float64{returnc.radius*c.radius*math.Pi}

    funcmain(){r1:=Rectangle{12,2}r2:=Rectangle{9,4}c1:=Circle{10}c2:=Circle{25}

    fmt.Println("Areaofr1is:",r1.area())fmt.Println("Areaofr2is:",r2.area())fmt.Println("Areaofc1is:",c1.area())fmt.Println("Areaofc2is:",c2.area())}

    Notesforusingmethods.

    Ifthenameofmethodsarethesamebuttheydon'tsharethesamereceivers,theyarenotthesame.Methodsareabletoaccessfieldswithinreceivers.Use.tocallamethodinthestruct,thesamewayfieldsarecalled.

    Figure2.9Methodsaredifferentindifferentstructs

    Intheexampleabove,thearea()methodsbelongtobothRectangleandCirclerespectively,sothereceiversareRectangleandCircle.

    Onethingthat'sworthnotingisthatthemethodwithadottedlinemeansthereceiverispassedbyvalue,notbyreference.Thedifferencebetweenthemisthatamethodcanchangeitsreceiver'svalueswhenthereceiverispassedbyreference,anditgetsacopyofthereceiverwhenthereceiverispassedbyvalue.

    Canthereceiveronlybeastruct?Ofcoursenot.Anytypecanbethereceiverofamethod.Youmaybeconfusedaboutcustomizedtypes.Structisaspecialkindofcustomizedtype-therearemorecustomizedtypes.

    Usethefollowingformattodefineacustomizedtype.

    typetypeNametypeLiteral

    Examplesofcustomizedtypes:

    typeagesint

    typemoneyfloat32

    typemonthsmap[string]int

  • m:=months{"January":31,"February":28,..."December":31,}

    Ihopethatyouknowhowtousecustomizedtypesnow.SimilartotypedefinC,weuseagestosubstituteintintheaboveexample.

    Let'sgetbacktotalkingaboutmethod.

    Youcanuseasmanymethodsincustomtypesasyouwant.

    packagemainimport"fmt"

    const(WHITE=iotaBLACKBLUEREDYELLOW)

    typeColorbyte

    typeBoxstruct{width,height,depthfloat64colorColor}

    typeBoxList[]Box//asliceofboxes

    func(bBox)Volume()float64{returnb.width*b.height*b.depth}

    func(b*Box)SetColor(cColor){b.color=c}

    func(blBoxList)BiggestsColor()Color{v:=0.00k:=Color(WHITE)for_,b:=rangebl{ifb.Volume()>v{v=b.Volume()k=b.color}}returnk}

    func(blBoxList)PaintItBlack(){fori,_:=rangebl{bl[i].SetColor(BLACK)}}

    func(cColor)String()string{strings:=[]string{"WHITE","BLACK","BLUE","RED","YELLOW"}returnstrings[c]}

    funcmain(){boxes:=BoxList{Box{4,4,4,RED},Box{10,10,1,YELLOW},Box{1,1,20,BLACK},Box{10,10,1,BLUE},Box{10,30,1,WHITE},Box{20,20,20,YELLOW},}

    fmt.Printf("Wehave%dboxesinourset\n",len(boxes))fmt.Println("Thevolumeofthefirstoneis",boxes[0].Volume(),"cm")

  • fmt.Println("Thecolorofthelastoneis",boxes[len(boxes)-1].color.String())fmt.Println("Thebiggestoneis",boxes.BiggestsColor().String())

    fmt.Println("Let'spaintthemallblack")boxes.PaintItBlack()fmt.Println("Thecolorofthesecondoneis",boxes[1].color.String())

    fmt.Println("Obviously,now,thebiggestoneis",boxes.BiggestsColor().String())}

    Wedefinesomeconstantsandcustomizedtypes.

    UseColorasaliasofbyte.DefineastructBoxwhichhasfieldsheight,width,lengthandcolor.DefineastructBoxListwhichhasBoxasitsfield.

    Thenwedefinedsomemethodsforourcustomizedtypes.

    Volume()usesBoxasitsreceiverandreturnsvolumeofBox.SetColor(cColor)changesBox'scolor.BiggestsColor()returnsthecolorwhichhasthebiggestvolume.PaintItBlack()setscolorforallBoxinBoxListtoblack.String()useColorasitsreceiver,returnsthestringformatofcolorname.

    Isitmuchclearerwhenweusewordstodescribeourrequirements?Weoftenwriteourrequirementsbeforewestartcoding.

    Let'stakealookatSetColormethod.ItsreceiverisapointerofBox.Yes,youcanuse*Boxasareceiver.Whydoweuseapointerhere?BecausewewanttochangeBox'scolorinthismethod.Thus,ifwedon'tuseapointer,itwillonlychangethevalueinsideacopyofBox.

    Ifweseethatareceiveristhefirstargumentofamethod,it'snothardtounderstandhowitworks.

    Youmightbeaskingwhywearen'tusing(*b).Color=cinsteadofb.Color=cintheSetColor()method.EitheroneisOKherebecauseGoknowshowtointerprettheassignment.DoyouthinkGoismorefascinatingnow?

    Youmayalsobeaskingwhetherweshoulduse(&bl[i]).SetColor(BLACK)inPaintItBlackbecausewepassapointertoSetColor.Again,eitheroneisOKbecauseGoknowshowtointerpretit!

    Welearnedaboutinheritanceoffieldsinthelastsection.Similarly,wealsohavemethodinheritanceinGo.Ifananonymousfieldhasmethods,thenthestructthatcontainsthefieldwillhaveallthemethodsfromitaswell.

    packagemainimport"fmt"

    typeHumanstruct{namestringageintphonestring}

    typeStudentstruct{Human//anonymousfieldschoolstring}

    typeEmployeestruct{Humancompanystring}

    Usepointerasreceiver

    Inheritanceofmethod

  • //defineamethodinHumanfunc(h*Human)SayHi(){fmt.Printf("Hi,Iam%syoucancallmeon%s\n",h.name,h.phone)}

    funcmain(){mark:=Student{Human{"Mark",25,"222-222-YYYY"},"MIT"}sam:=Employee{Human{"Sam",45,"111-888-XXXX"},"GolangInc"}

    mark.SayHi()sam.SayHi()}

    IfwewantEmployeetohaveitsownmethodSayHi,wecandefineamethodthathasthesamenameinEmployee,anditwillhideSayHiinHumanwhenwecallit.

    packagemainimport"fmt"

    typeHumanstruct{namestringageintphonestring}

    typeStudentstruct{Humanschoolstring}

    typeEmployeestruct{Humancompanystring}

    func(h*Human)SayHi(){fmt.Printf("Hi,Iam%syoucancallmeon%s\n",h.name,h.phone)}

    func(e*Employee)SayHi(){fmt.Printf("Hi,Iam%s,Iworkat%s.Callmeon%s\n",e.name,e.company,e.phone)//Yesyoucansplitinto2lineshere.}

    funcmain(){mark:=Student{Human{"Mark",25,"222-222-YYYY"},"MIT"}sam:=Employee{Human{"Sam",45,"111-888-XXXX"},"GolangInc"}

    mark.SayHi()sam.SayHi()}

    YouareabletowriteanObject-orientedprogramnow,andmethodsuseruleofcapitallettertodecidewhetherpublicorprivateaswell.

    DirectoryPrevioussection:structNextsection:interface

    Methodoverload

    Links

  • OneofthesubtlestdesignfeaturesinGoareinterfaces.Afterreadingthissection,youwilllikelybeimpressedbytheirimplementation.

    Inshort,aninterfaceisasetofmethodsthatweusetodefineasetofactions.

    Liketheexamplesinprevioussections,bothStudentandEmployeecanSayHi(),buttheydon'tdothesamething.

    Let'sdosomemorework.We'lladdonemoremethodSing()tothem,alongwiththeBorrowMoney()methodtoStudentandtheSpendSalary()methodtoEmployee.

    Now,StudenthasthreemethodscalledSayHi(),Sing()andBorrowMoney(),andEmployeehasSayHi(),Sing()andSpendSalary().

    ThiscombinationofmethodsiscalledaninterfaceandisimplementedbybothStudentandEmployee.So,StudentandEmployeeimplementtheinterface:SayHi()andSing().Atthesametime,Employeedoesn'timplementtheinterface:SayHi(),Sing(),BorrowMoney(),andStudentdoesn'timplementtheinterface:SayHi(),Sing(),SpendSalary().ThisisbecauseEmployeedoesn'thavethemethodBorrowMoney()andStudentdoesn'thavethemethodSpendSalary().

    Aninterfacedefinesasetofmethods,soifatypeimplementsallthemethodswesaythatitimplementstheinterface.

    typeHumanstruct{namestringageintphonestring}

    typeStudentstruct{Humanschoolstringloanfloat32}

    typeEmployeestruct{Humancompanystringmoneyfloat32}

    func(h*Human)SayHi(){fmt.Printf("Hi,Iam%syoucancallmeon%s\n",h.name,h.phone)}

    func(h*Human)Sing(lyricsstring){fmt.Println("Lala,lalala,lalalalala...",lyrics)}

    func(h*Human)Guzzle(beerSteinstring){fmt.Println("GuzzleGuzzleGuzzle...",beerStein)}

    //EmployeeoverloadsSayhifunc(e*Employee)SayHi(){fmt.Printf("Hi,Iam%s,Iworkat%s.Callmeon%s\n",e.name,e.company,e.phone)//Yesyoucansplitinto2lineshere.}

    func(s*Student)BorrowMoney(amountfloat32){

    2.6Interface

    Interface

    Whatisaninterface

    TypeofInterface

  • s.loan+=amount//(againandagainand...)}

    func(e*Employee)SpendSalary(amountfloat32){e.money-=amount//Morevodkaplease!!!Getmethroughtheday!}

    //defineinterfacetypeMeninterface{SayHi()Sing(lyricsstring)Guzzle(beerSteinstring)}

    typeYoungChapinterface{SayHi()Sing(songstring)BorrowMoney(amountfloat32)}

    typeElderlyGentinterface{SayHi()Sing(songstring)SpendSalary(amountfloat32)}

    Weknowthataninterfacecanbeimplementedbyanytype,andonetypecanimplementmanyinterfacessimultaneously.

    Notethatanytypeimplementstheemptyinterfaceinterface{}becauseitdoesn'thaveanymethodsandalltypeshavezeromethodsbydefault.

    Sowhatkindofvaluescanbeputintheinterface?Ifwedefineavariableasatypeinterface,anytypethatimplementstheinterfacecanassignedtothisvariable.

    Liketheaboveexample,ifwedefineavariable"m"asinterfaceMen,thenanyoneofStudent,HumanorEmployeecanbeassignedto"m".SowecouldhaveasliceofMen,andanytypethatimplementsinterfaceMencanassigntothisslice.Beawarehoweverthatthesliceofinterfacedoesn'thavethesamebehaviorasasliceofothertypes.

    packagemain

    import"fmt"

    typeHumanstruct{namestringageintphonestring}

    typeStudentstruct{Humanschoolstringloanfloat32}

    typeEmployeestruct{Humancompanystringmoneyfloat32}

    func(hHuman)SayHi(){fmt.Printf("Hi,Iam%syoucancallmeon%s\n",h.name,h.phone)}

    func(hHuman)Sing(lyricsstring){fmt.Println("Lalalala...",lyrics)}

    func(eEmployee)SayHi(){fmt.Printf("Hi,Iam%s,Iworkat%s.Callmeon%s\n",e.name,e.company,e.phone)//Yesyoucansplitinto2lineshere.

    Valueofinterface

  • }//InterfaceMenimplementedbyHuman,StudentandEmployeetypeMeninterface{SayHi()Sing(lyricsstring)}

    funcmain(){mike:=Student{Human{"Mike",25,"222-222-XXX"},"MIT",0.00}paul:=Student{Human{"Paul",26,"111-222-XXX"},"Harvard",100}sam:=Employee{Human{"Sam",36,"444-222-XXX"},"GolangInc.",1000}Tom:=Employee{Human{"Sam",36,"444-222-XXX"},"ThingsLtd.",5000}

    //defineinterfaceivariMen

    //icanstoreStudenti=mikefmt.Println("ThisisMike,aStudent:")i.SayHi()i.Sing("Novemberrain")

    //icanstoreEmployeei=Tomfmt.Println("ThisisTom,anEmployee:")i.SayHi()i.Sing("Borntobewild")

    //sliceofMenfmt.Println("Let'suseasliceofMenandseewhathappens")x:=make([]Men,3)//thesethreeelementsaredifferenttypesbuttheyallimplementedinterfaceMenx[0],x[1],x[2]=paul,sam,mike

    for_,value:=rangex{value.SayHi()}}

    Aninterfaceisasetofabstractmethods,andcanbeimplementedbynon-interfacetypes.Itcannotthereforeimplementitself.

    Anemptyinterfaceisaninterfacethatdoesn'tcontainanymethods,soalltypesimplementanemptyinterface.Thisfactisveryusefulwhenwewanttostorealltypesatsomepoint,andissimilartovoid*inC.

    //defineaasemptyinterfacevarainterface{}variint=5s:="Helloworld"//acanstorevalueofanytypea=ia=s

    Ifafunctionusesanemptyinterfaceasitsargumenttype,itcanacceptanytype;ifafunctionusesemptyasitsreturnvaluetype,itcanreturnanytype.

    Anyvariablecanbeusedinaninterface.Sohowcanweusethisfeaturetopassanytypeofvariabletoafunction?

    Forexampleweusefmt.Printlnalot,buthaveyouevernoticedthatitcanacceptanytypeofargument?Lookingattheopensourcecodeoffmt,weseethefollowingdefinition.

    typeStringerinterface{String()string}

    Emptyinterface

    Methodargumentsofaninterface

  • ThismeansanytypethatimplementsinterfaceStringercanbepassedtofmt.Printlnasanargument.Let'sproveit.

    packagemain

    import("fmt""strconv")

    typeHumanstruct{namestringageintphonestring}

    //Humanimplementedfmt.Stringerfunc(hHuman)String()string{return"Name:"+h.name+",Age:"+strconv.Itoa(h.age)+"years,Contact:"+h.phone}

    funcmain(){Bob:=Human{"Bob",39,"000-7777-XXX"}fmt.Println("ThisHumanis:",Bob)}

    LookingbacktotheexampleofBox,youwillfindthatColorimplementsinterfaceStringeraswell,soweareabletocustomizetheprintformat.Ifwedon'timplementthisinterface,fmt.Printlnprintsthetypewithitsdefaultformat.

    fmt.Println("Thebiggestoneis",boxes.BiggestsColor().String())fmt.Println("Thebiggestoneis",boxes.BiggestsColor())

    Attention:Ifthetypeimplementedtheinterfaceerror,fmtwillcallerror(),soyoudon'thavetoimplementStringeratthispoint.

    Ifavariableisthetypethatimplementsaninterface,weknowthatanyothertypethatimplementsthesameinterfacecanbeassignedtothisvariable.Thequestionishowcanweknowthespecifictypestoredintheinterface.TherearetwowayswhichIwillshowyou.

    AssertionofComma-okpattern

    Gohasthesyntaxvalue,ok:=element.(T).Thischeckstoseeifthevariableisthetypethatweexpect,where"value"isthevalueofthevariable,"ok"isavariableofbooleantype,"element"istheinterfacevariableandtheTisthetypeofassertion.

    Iftheelementisthetypethatweexpect,okwillbetrue,falseotherwise.

    Let'suseanexampletoseemoreclearly.

    packagemain

    import("fmt""strconv")

    typeElementinterface{}typeList[]Element

    typePersonstruct{namestringageint}

    Typeofvariableinaninterface

  • func(pPerson)String()string{return"(name:"+p.name+"-age:"+strconv.Itoa(p.age)+"years)"}

    funcmain(){list:=make(List,3)list[0]=1//anintlist[1]="Hello"//astringlist[2]=Person{"Dennis",70}

    forindex,element:=rangelist{ifvalue,ok:=element.(int);ok{fmt.Printf("list[%d]isanintanditsvalueis%d\n",index,value)}elseifvalue,ok:=element.(string);ok{fmt.Printf("list[%d]isastringanditsvalueis%s\n",index,value)}elseifvalue,ok:=element.(Person);ok{fmt.Printf("list[%d]isaPersonanditsvalueis%s\n",index,value)}else{fmt.Printf("list[%d]isofadifferenttype\n",index)}}}

    It'squiteeasytousethispattern,butifwehavemanytypestotest,we'dbetteruseswitch.

    switchtest

    Let'suseswitchtorewritetheaboveexample.

    packagemain

    import("fmt""strconv")

    typeElementinterface{}typeList[]Element

    typePersonstruct{namestringageint}

    func(pPerson)String()string{return"(name:"+p.name+"-age:"+strconv.Itoa(p.age)+"years)"}

    funcmain(){list:=make(List,3)list[0]=1//anintlist[1]="Hello"//astringlist[2]=Person{"Dennis",70}

    forindex,element:=rangelist{switchvalue:=element.(type){caseint:fmt.Printf("list[%d]isanintanditsvalueis%d\n",index,value)casestring:fmt.Printf("list[%d]isastringanditsvalueis%s\n",index,value)casePerson:fmt.Printf("list[%d]isaPersonanditsvalueis%s\n",index,value)default:fmt.Println("list[%d]isofadifferenttype",index)}}}

    Onethingyoushouldrememberisthatelement.(type)cannotbeusedoutsideoftheswitchbody,whichmeansinthatcaseyouhavetousethecomma-okpattern.

    Embeddedinterfaces

  • ThemostbeautifulthingisthatGohasalotofbuilt-inlogicsyntax,suchasanonymousfieldsinstruct.Notsuprisingly,wecanuseinterfacesasanonymousfieldsaswell,butwecallthemEmbeddedinterfaces.Here,wefollowthesamerulesasanonymousfields.Morespecifically,ifaninterfacehasanotherinterfaceembeddedwithinit,itwillhaveasifithasallthemethodsthattheembeddedinterfacehas.

    Wecanseethatthesourcefileincontainer/heaphasthefollowingdefinition:

    typeInterfaceinterface{sort.Interface//embeddedsort.InterfacePush(xinterface{})//aPushmethodtopushelementsintotheheapPop()interface{}//aPopelementsthatpopselementsfromtheheap}

    Weseethatsort.Interfaceisanembeddedinterface,sotheaboveInterfacehasthethreemethodscontainedwithinthesort.Interfaceimplicitly.

    typeInterfaceinterface{//Lenisthenumberofelementsinthecollection.Len()int//Lessreturnswhethertheelementwithindexishouldsort//beforetheelementwithindexj.Less(i,jint)bool//Swapswapstheelementswithindexesiandj.Swap(i,jint)}

    Anotherexampleistheio.ReadWriterinpackageio.

    //io.ReadWritertypeReadWriterinterface{ReaderWriter}

    ReflectioninGoisusedfordetermininginformationatruntime.Weusethereflectpackage,andthisofficialarticleexplainshowreflectworksinGo.

    Therearethreestepsinvolvedwhenusingreflect.First,weneedtoconvertaninterfacetoreflecttypes(reflect.Typeorreflect.Value,thisdependsonthesituation).

    t:=reflect.TypeOf(i)//getmeta-dataintypei,andusettogetallelementsv:=reflect.ValueOf(i)//getactualvalueintypei,andusevtochangeitsvalue

    Afterthat,wecanconvertthereflectedtypestogetthevaluesthatweneed.

    varxfloat64=3.4v:=reflect.ValueOf(x)fmt.Println("type:",v.Type())fmt.Println("kindisfloat64:",v.Kind()==reflect.Float64)fmt.Println("value:",v.Float())

    Finally,ifwewanttochangethevaluesofthereflectedtypes,weneedtomakeitmodifiable.Asdiscussedearlier,thereisadifferencebetweenpassbyvalueandpassbyreference.Thefollowingcodewillnotcompile.

    varxfloat64=3.4

    Reflection

  • v:=reflect.ValueOf(x)v.SetFloat(7.1)

    Instead,wemustusethefollowingcodetochangethevaluesfromreflecttypes.

    varxfloat64=3.4p:=reflect.ValueOf(&x)v:=p.Elem()v.SetFloat(7.1)

    Wehavejustdiscussedthebasicsofreflection,howeveryoumustpracticemoreinordertounderstandmore.

    DirectoryPrevioussection:Object-orientedNextsection:Concurrency

    Links

  • ItissaidthatGoistheClanguageofthe21stcentury.Ithinktherearetworeasons:first,Goisasimplelanguage;second,concurrencyisahottopicintoday'sworld,andGosupportsthisfeatureatthelanguagelevel.

    goroutinesandconcurrencyarebuiltintothecoredesignofGo.They'resimilartothreadsbutworkdifferently.Morethanadozengoroutinesmaybeonlyhave5or6underlyingthreads.Goalsogivesyoufullsupporttosharingmemoryinyourgoroutines.Onegoroutineusuallyuses4~5KBofstackmemory.Therefore,it'snothardtorunthousandsofgoroutinesonasinglecomputer.Agoroutineismorelightweight,moreefficientandmoreconvenientthansystemthreads.

    goroutinesrunonthethreadmanageratruntimeinGo.Weusethegokeywordtocreateanewgoroutine,whichisafunctionattheunderlyinglevel(main()isagoroutine).

    gohello(a,b,c)

    Let'sseeanexample.

    packagemain

    import("fmt""runtime")

    funcsay(sstring){fori:=0;i0!buffernon-blockuntilnelementsinthechannel

    Youcantrythefollowingcodeonyourcomputerandchangesomevalues.

    packagemain

    import"fmt"

    funcmain(){c:=make(chanint,2)//change2to1willhaveruntimeerror,but3isfinec

  • import"fmt"

    funcfibonacci(c,quitchanint){x,y:=1,1for{select{casec

  • Exitsthecurrentgoroutine,butdeferedfunctionswillbeexecutedasusual.

    runtime.Gosched()

    Letstheschedulerexecuteothergoroutinesandcomesbackatsomepoint.

    runtime.NumCPU()int

    ReturnsthenumberofCPUcores

    runtime.NumGoroutine()int

    Returnsthenumberofgoroutines

    runtime.GOMAXPROCS(nint)int

    SetshowmanyCPUcoresyouwanttouse

    DirectoryPrevioussection:interfaceNextsection:Summary

    Links

  • Inthischapter,wemainlyintroducedthe25Gokeywords.Let'sreviewwhattheyareandwhattheydo.

    breakdefaultfuncinterfaceselectcasedefergomapstructchanelsegotopackageswitchconstfallthroughifrangetypecontinueforimportreturnvar

    varandconstareusedtodefinevariablesandconstants.packageandimportareforpackageuse.funcisusedtodefinefunctionsandmethods.returnisusedtoreturnvaluesinfunctionsormethods.deferisusedtodefinedeferfunctions.goisusedtostartanewgoroutine.selectisusedtoswitchovermultiplechannelsforcommunication.interfaceisusedtodefineinterfaces.structisusedtodefinespecialcustomizedtypes.break,case,continue,for,fallthrough,else,if,switch,gotoanddefaultwereintroducedinsection2.3.chanisthetypeofchannelforcommunicationamonggoroutines.typeisusedtodefinecustomizedtypes.mapisusedtodefinemapwhichissimilartohashtablesinotherlanguages.rangeisusedforreadingdatafromslice,mapandchannel.

    Ifyouunderstandhowtousethese25keywords,you'velearnedalotofGoalready.

    DirectoryPrevioussection:ConcurrencyNextchapter:Webfoundation

    2.8Summary

    Links

  • ThereasonyouarereadingthisbookisthatyouwanttolearntobuildwebapplicationsinGo.AsI'vesaidbefore,Goprovidesmanypowerfulpackageslikehttp.Thesepackagescanhelpyoualotwhentryingtobuildwebapplications.I'llteachyoueverythingyouneedtoknowinthefollowingchapters,andwe'lltalkaboutsomeconceptsofthewebandhowtorunwebapplicationsinGointhischapter.

    DirectoryPreviouschapter:Chapter2SummaryNextsection:Webworkingprinciples

    3Webfoundation

    Links

  • Everytimeyouopenyourbrowsers,typesomeURLsandpressenter,youwillseebeautifulwebpagesappearonyourscreen.Butdoyouknowwhatishappeningbehindthesesimpleactions?

    Normally,yourbrowserisaclient.AfteryoutypeaURL,ittakesthehostpartoftheURLandsendsittoaDNSserverinordertogettheIPaddressofthehost.ThenitconnectstotheIPaddressandaskstosetupaTCPconnection.ThebrowsersendsHTTPrequeststhroughtheconnection.TheserverhandlesthemandreplieswithHTTPresponsescontainingthecontentthatmakeupthewebpage.Finally,thebrowserrendersthebodyofthewebpageanddisconnectsfromtheserver.

    Figure3.1Processesofusersvisitawebsite

    Awebserver,alsoknownasanHTTPserver,usestheHTTPprotocoltocommunicatewithclients.Allwebbrowserscanbeconsideredclients.

    Wecandividetheweb'sworkingprinciplesintothefollowingsteps:

    ClientusesTCP/IPprotocoltoconnecttoserver.ClientsendsHTTPrequestpackagestoserver.ServerreturnsHTTPresponsepackagestoclient.Iftherequestedresourcesincludedynamicscripts,servercallsscriptenginefirst.Clientdisconnectsfromserver,startsrenderingHTML.

    ThisisasimpleworkflowofHTTPaffairs-noticethattheserverclosesitsconnectionsafteritsendsdatatotheclients,thenwaitsforthenextrequest.

    WealwaysuseURLstoaccesswebpages,butdoyouknowhowURLswork?

    ThefullnameofaURLisUniformResourceLocator.It'sfordescribingresourcesontheinternetanditsbasicformisasfollows.

    scheme://host[:port#]/path/.../[?query-string][#anchor]schemeassignunderlyingprotocol(suchasHTTP,HTTPS,FTP)hostIPordomainnameofHTTPserverport#defaultportis80,anditcanbeomittedinthiscase.Ifyouwanttouseotherports,youmustspecifywhichport.Forexample,http://www.cnblogs.com:8080/pathresourcespathquery-stringdataaresenttoserveranchoranchor

    DNSisanabbreviationofDomainNameSystem.It'sthenamingsystemforcomputernetworkservices,anditconvertsdomainnamestoactualIPaddresses,justlikeatranslator.

    Figure3.2DNSworkingprinciples

    Tounderstandmoreaboutitsworkingprinciple,let'sseethedetailedDNSresolutionprocessasfollows.

    1. Aftertypingthedomainnamewww.qq.cominthebrowser,theoperatingsystemwillcheckifthereareanymappingrelationshipsinthehosts'filesforthisdomainname.Ifso,thenthedomainnameresolutioniscomplete.

    Webworkingprinciples

    URLandDNSresolution

  • 2. Ifnomappingrelationshipsexistinthehosts'files,theoperatingsystemwillcheckifanycacheexistsintheDNS.Ifso,thenthedomainnameresolutioniscomplete.

    3. IfnomappingrelationshipsexistinboththehostandDNScache,theoperatingsystemfindsthefirstDNSresolutionserverinyourTCP/IPsettings,whichislikelyyourlocalDNSserver.WhenthelocalDNSserverreceivesthequery,ifthedomainnamethatyouwanttoqueryiscontainedwithinthelocalconfigurationofitsregionalresources,itreturnstheresultstotheclient.ThisDNSresolutionisauthoritative.

    4. IfthelocalDNSserverdoesn'tcontainthedomainnamebutamappingrelationshipexistsinthecache,thelocalDNSservergivesbackthisresulttotheclient.ThisDNSresolutionisnotauthoritative.

    5. IfthelocalDNSservercannotresolvethisdomainnameeitherbyconfigurationofregionalresourcesorcache,itwillproceedtothenextstep,whichdependsonthelocalDNSserver'ssettings.-IfthelocalDNSserverdoesn'tenableforwarding,itroutestherequesttotherootDNSserver,thenreturnstheIPaddressofatoplevelDNSserverwhichmayknowthedomainname,.cominthiscase.IfthefirsttoplevelDNSserverdoesn'trecognizethedomainname,itagainreroutestherequesttothenexttoplevelDNSserveruntilitreachesonethatrecognizesthedomainname.ThenthetoplevelDNSserverasksthisnextlevelDNSserverfortheIPaddresscorrespondingtowww.qq.com.-IfthelocalDNSserverhasforwardingenabled,itsendstherequesttoanupperlevelDNSserver.IftheupperlevelDNSserveralsodoesn'trecognizethedomainname,thentherequestkeepsgettingreroutedtohigherlevelsuntilitfinallyreachesaDNSserverwhichrecognizesthedomainname.

    WhetherornotthelocalDNSserverenablesforwarding,theIPaddressofthedomainnamealwaysreturnstothelocalDNSserver,andthelocalDNSserversendsitbacktotheclient.

    Figure3.3DNSresolutionworkflow

    Recursivequeryprocesssimplymeansthattheenquirerschangeintheprocess.EnquirersdonotchangeinIterativequeryprocesses.

    NowweknowclientsgetIPaddressesintheend,sothebrowsersarecommunicatingwithserversthroughIPaddresses.

    TheHTTPprotocolisacorepartofwebservices.It'simportanttoknowwhattheHTTPprotocolisbeforeyouunderstandhowthewebworks.

    HTTPistheprotocolthatisusedtofacilitatecommunicationbetweenbrowsersandwebservers.ItisbasedontheTCPprotocolandusuallyusesport80onthesideofthewebserver.Itisaprotocolthatutilizestherequest-responsemodel-clientssendrequestsandserversrespond.AccordingtotheHTTPprotocol,clientsalwayssetupnewconnectionsandsendHTTPrequeststoservers.Serversarenotabletoconnecttoclientsproactively,orestablishcallbackconnections.Theconnectionbetweenaclientandaservercanbeclosedbyeitherside.Forexample,youcancancelyourdownloadrequestandHTTPconnectionandyourbrowserwilldisconnectfromtheserverbeforeyoufinishdownloading.

    TheHTTPprotocolisstateless,whichmeanstheserverhasnoideaabouttherelationshipbetweenthetwoconnectionseventhoughtheyarebothfromsameclient.Tosolvethisproblem,webapplicationsusecookiestomaintainthestateofconnections.

    BecausetheHTTPprotocolisbasedontheTCPprotocol,allTCPattackswillaffectHTTPcommunicationsinyourserver.ExamplesofsuchattacksareSYNflooding,DoSandDDoSattacks.

    Requestpackagesallhavethreeparts:requestline,requestheader,andbody.Thereisoneblanklinebetweenheaderandbody.

    GET/domains/example/HTTP/1.1//requestline:requestmethod,URL,protocolanditsversionHostwww.iana.org//domainnameUser-AgentMozilla/5.0(WindowsNT6.1)AppleWebKit/537.4(KHTML,likeGecko)Chrome/22.0.1229.94Safari/537.4//browserinformation

    HTTPprotocol

    HTTPrequestpackage(browserinformation)

  • Accepttext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8//minethatclientscanacceptAccept-Encodinggzip,deflate,sdch//streamcompressionAccept-CharsetUTF-8,*;q=0.5//charactersetinclientside//blankline//body,requestresourcearguments(forexample,argumentsinPOST)

    Weusefiddlertogetthefollowingrequestinformation.

    Figure3.4InformationofaGETrequestcaughtbyfiddler

    Figure3.5InformationofaPOSTrequestcaughtbyfiddler

    WecanseethatGETdoesnothavearequestbody,unlikePOST,whichdoes.

    TherearemanymethodsyoucanusetocommunicatewithserversinHTTP;GET,POST,PUTandDELETEarethe4basicmethodsthatwetypicallyuse.AURLrepresentsaresourceonanetwork,sothese4methodsdefinethequery,change,addanddeleteoperationsthatcanactontheseresources.GETandPOSTareverycommonlyusedinHTTP.GETcanappendqueryparameterstotheURL,using?toseparatetheURLandparametersand&betweenthearguments,likeEditPosts.aspx?name=test1&id=123456.POSTputsdataintherequestbodybecausetheURLimplementsalengthlimitationviathebrowser.Thus,POSTcansubmitmuchmoredatathanGET.Also,whenwesubmitusernamesandpasswords,wedon'twantthiskindofinformationtoappearintheURL,soweusePOSTtokeeptheminvisible.

    Let'sseewhatinformationiscontainedintheresponsepackages.

    HTTP/1.1200OK//statuslineServer:nginx/1.0.8//webserversoftwareanditsversionintheservermachineDate:Date:Tue,30Oct201204:14:25GMT//respondedtimeContent-Type:text/html//respondeddatatypeTransfer-Encoding:chunked//itmeansdataweresentinfragmentsConnection:keep-alive//keepconnectionContent-Length:90//lengthofbody//blankline

  • Thetermstatelessdoesn'tmeanthattheserverhasnoabilitytokeepaconnection.Itsimplymeansthattheserverdoesn'trecognizeanyrelationshipsbetweenanytworequests.

    InHTTP/1.1,Keep-aliveisusedbydefault.Ifclientshaveadditionalrequests,theywillusethesameconnectionforthem.

    NoticethatKeep-alivecannotmaintianoneconnectionforever;theapplicationrunningintheserverdeterminesthelimitwithwhichtokeeptheconnectionalivefor,andinmostcasesyoucanconfigurethislimit.

    Figure3.7Allpackagesforopeningonewebpage

    Wecanseetheentirecommunicationprocessbetweenclientandserverfromtheabovepicture.Youmaynoticethattherearemanyresourcefilesinthelist;thesearecalledstaticfiles,andGohasspecializedprocessingmethodsforthesefiles.

    Thisisthemostimportantfunctionofbrowsers:torequestforaURLandretrievedatafromwebservers,thenrendertheHTML.IfitfindssomefilesintheDOMsuchasCSSorJSfiles,browserswillrequesttheseresourcesfromtheserveragainuntilalltheresourcesfinishrenderingonyourscreen.

    ReducingHTTPrequesttimesisonewayofimprovingtheloadingspeedofwebpages.ByreducingthenumberofCSSandJSfilesthatneedtobeloaded,bothrequestlatenciesandpressureonyourwebserverscanbereducedatthesametime.

    DirectoryPrevioussection:WebfoundationNextsection:Buildasimplewebserver

    Requestinstance

    Links

  • We'vediscussedthatwebapplicationsarebasedontheHTTPprotocol,andGoprovidesfullHTTPsupportinthenet/httppackage.It'sveryeasytosetawebserverupusingthispackage.

    packagemain

    import("fmt""net/http""strings""log")

    funcsayhelloName(whttp.ResponseWriter,r*http.Request){r.ParseForm()//parsearguments,youhavetocallthisbyyourselffmt.Println(r.Form)//printforminformationinserversidefmt.Println("path",r.URL.Path)fmt.Println("scheme",r.URL.Scheme)fmt.Println(r.Form["url_long"])fork,v:=ranger.Form{fmt.Println("key:",k)fmt.Println("val:",strings.Join(v,""))}fmt.Fprintf(w,"Helloastaxie!")//senddatatoclientside}

    funcmain(){http.HandleFunc("/",sayhelloName)//setroutererr:=http.ListenAndServe(":9090",nil)//setlistenportiferr!=nil{log.Fatal("ListenAndServe:",err)}}

    Afterweexecutetheabovecode,theserverbeginslisteningtoport9090inlocalhost.

    Openyourbrowserandvisithttp://localhost:9090.YoucanseethatHelloastaxieisonyourscreen.

    Let'stryanotheraddresswithadditionalarguments:http://localhost:9090/?url_long=111&url_long=222

    Nowlet'sseewhathappensonboththeclientandserversides.

    Youshouldseethefollowinginformationontheserverside:

    Figure3.8Serverprintedinformation

    Asyoucansee,weonlyneedtocalltwofunctionsinordertobuildasimplewebserver.

    IfyouareworkingwithPHP,you'reprobablyaskingwhetherornotweneedsomethinglikeNginxorApache.Theanswerisweno,sinceGolistenstotheTCPportbyitself,andthefunctionsayhelloNameisthelogicfunctionjustlikeacontrollerinPHP.

    IfyouareworkingwithPythonyoushouldknowtornado,andtheaboveexampleisverysimilartothat.

    IfyouareworkingwithRuby,youmaynoticeitislikescript/serverinROR.

    Weusedtwosimplefunctionstosetupasimplewebserverinthissection,andthissimpleserveralreadyhasthecapacity

    3.2Buildasimplewebserver

    Usehttppackagesetupawebserver

  • forhighconcurrencyoperations.Wewilltalkabouthowtoutilizethisinthenexttwosections.

    DirectoryPrevioussection:WebworkingprinciplesNextsection:HowGoworkswithweb

    Links

  • Welearnedtousethenet/httppackagetobuildasimplewebserverintheprevioussection,andallthoseworkingprinciplesarethesameasthosewewilltalkaboutinthefirstsectionofthischapter.

    Request:requestdatafromusers,includingPOST,GET,CookieandURL.

    Response:responsedatafromservertoclients.

    Conn:connectionsbetweenclientsandservers.

    Handler:Requesthandlinglogicandresponsegeneration.

    ThefollowingpictureshowstheworkflowofaGowebserver.

    Figure3.9httpworkflow

    1. Createalisteningsocket,listentoaportandwaitforclients.2. Acceptrequestsfromclients.3. Handlerequests,readHTTPheader.IftherequestusesPOSTmethod,readdatainthemessagebodyandpassthem

    tohandlers.Finally,socketreturnsresponsedatatoclients.

    Onceweknowtheanswerstothethreefollowingquestions,it'seasytoknowhowthewebworksinGo.

    Howdowelistentoaport?Howdoweacceptclientrequests?Howdoweallocatehandlers?

    IntheprevioussectionwesawthatGousesListenAndServetohandlethesesteps:initializeaserverobject,callnet.Listen("tcp",addr)tosetupaTCPlistenerandlistentoaspecificaddressandport.

    Let'stakealookatthehttppackage'ssourcecode.

    //Buildversiongo1.1.2.func(srv*Server)Serve(lnet.Listener)error{deferl.Close()vartempDelaytime.Duration//howlongtosleeponacceptfailurefor{rw,e:=l.Accept()ife!=nil{ifne,ok:=e.(net.Error);ok&&ne.Temporary(){iftempDelay==0{tempDelay=5*time.Millisecond}else{tempDelay*=2}ifmax:=1*time.Second;tempDelay>max{tempDelay=max}log.Printf("http:Accepterror:%v;retryingin%v",e,tempDelay)time.Sleep(tempDelay)continue}returne

    3.3HowGoworkswithweb

    Conceptsinwebprinciples

    httppackageoperatingmechanism

  • }tempDelay=0c,err:=srv.newConn(rw)iferr!=nil{continue}goc.serve()}}

    Howdoweacceptclientrequestsafterwebeginlisteningtoaport?Inthesourcecode,wecanseethatsrv.Serve(net.Listener)iscalledtohandleclientrequests.Inthebodyofthefunctionthereisafor{}.Itacceptsarequest,createsanewconnectionthenstartsanewgoroutine,passingtherequestdatatothegoc.serve()goroutine.ThisishowGosupportshighconcurrency,andeverygoroutineisindependent.

    Howdoweusespecificfunctionstohandlerequests?connparsesrequestc.ReadRequest()atfirst,thengetsthecorrespondinghandler:handler:=c.server.HandlerwhichisthesecondargumentwepassedwhenwecalledListenAndServe.Becausewepassednil,Gousesitsdefaulthandlerhandler=DefaultServeMux.SowhatisDefaultServeMuxdoinghere?Well,itstheroutervariablewhichcancallhandlerfunctionsforspecificURLs.Didwesetthis?Yes,wedid.Wedidthisinthefirstlinewhereweusedhttp.HandleFunc("/",sayhelloName).We'reusingthisfunctiontoregistertherouterruleforthe"/"path.WhentheURLis/,theroutercallsthefunctionsayhelloName.DefaultServeMuxcallsServerHTTPtogethandlerfunctionsfordifferentpaths,callingsayhelloNameinthisspecificcase.Finally,theserverwritesdataandrespondstoclients.

    Detailedworkflow:

    Figure3.10WorkflowofhandlinganHTTPrequest

    IthinkyoushouldknowhowGorunswebserversnow.

    DirectoryPrevioussection:BuildasimplewebserverNextsection:Getintohttppackage

    Links

  • Inprevioussections,welearnedabouttheworkflowofthewebandtalkedalittlebitaboutGo'shttppackage.Inthissection,wearegoingtolearnabouttwocorefunctionsinthehttppackage:ConnandServeMux.

    UnlikenormalHTTPservers,GousesgoroutinesforeveryjobinitiatedbyConninordertoachievehighconcurrencyandperformance,soeveryjobisindependent.

    Gousesthefollowingcodetowaitfornewconnectionsfromclients.

    c,err:=srv.newConn(rw)iferr!=nil{continue}goc.serve()

    Asyoucansee,itcreatesanewgoroutineforeveryconnection,andpassesthehandlerthatisabletoreaddatafromtherequesttothegoroutine.

    WeusedGo'sdefaultrouterinprevioussectionswhendiscussingconn.server,withtherouterpassingrequestdatatoaback-endhandler.

    Thestructofthedefaultrouter:

    typeServeMuxstruct{musync.RWMutex//becauseofconcurrency,wehavetouseamutexheremmap[string]muxEntry//routerrules,everystringmappingtoahandler}

    ThestructofmuxEntry:

    typemuxEntrystruct{explicitbool//exactmatchornothHandler}

    TheinterfaceofHandler:

    typeHandlerinterface{ServeHTTP(ResponseWriter,*Request)//routingimplementer}

    Handlerisaninterface,butifthefunctionsayhelloNamedidn'timplementthisinterface,thenhowdidweadditashandler?TheanswerliesinanothertypecalledHandlerFuncinthehttppackage.WecalledHandlerFunctodefineoursayhelloNamemethod,sosayhelloNameimplementedHandleratthesametime.It'slikewe'recallingHandlerFunc(f),andthefunctionfisforceconvertedtotypeHandlerFunc.

    typeHandlerFuncfunc(ResponseWriter,*Request)

    3.4Getintohttppackage

    goroutineinConn

    CustomizedServeMux

  • //ServeHTTPcallsf(w,r).func(fHandlerFunc)ServeHTTP(wResponseWriter,r*Request){f(w,r)}

    Howdoestheroutercallhandlersafterwesettherouterrules?

    Theroutercallsmux.handler.ServeHTTP(w,r)whenitreceivesrequests.Inotherwords,itcallstheServeHTTPinterfaceofthehandlerswhichhaveimplementedit.

    Now,let'sseehowmux.handlerworks.

    func(mux*ServeMux)handler(r*Request)Handler{mux.mu.RLock()defermux.mu.RUnlock()

    //Host-specificpatterntakesprecedenceovergenericonesh:=mux.match(r.Host+r.URL.Path)ifh==nil{h=mux.match(r.URL.Path)}ifh==nil{h=NotFoundHandler()}returnh}

    Therouterusestherequest'sURLasakeytofindthecorrespondinghandlersavedinthemap,thencallshandler.ServeHTTPtoexecutefunctionstohandlethedata.

    Youshouldunderstandthedefaultrouter'sworkflowbynow,andGoactuallysupportscustomizedrouters.ThesecondargumentofListenAndServeisforconfiguringcustomizedrouters.It'saninterfaceofHandler.Therefore,anyrouterthatimplementstheHandlerinterfacecanbeused.

    Thefollowingexampleshowshowtoimplementasimplerouter.

    packagemain

    import("fmt""net/http")

    typeMyMuxstruct{}

    func(p*MyMux)ServeHTTP(whttp.ResponseWriter,r*http.Request){ifr.URL.Path=="/"{sayhelloName(w,r)return}http.NotFound(w,r)return}

    funcsayhelloName(whttp.ResponseWriter,r*http.Request){fmt.Fprintf(w,"Hellomyroute!")}

    funcmain(){mux:=&MyMux{}http.ListenAndServe(":9090",mux)}

    Gocodeexecutionflow

  • Let'stakealookatthewholeexecutionflow.

    Callhttp.HandleFunc1. CallHandleFuncofDefaultServeMux2. CallHandleofDefaultServeMux3. Addrouterrulestomap[string]muxEntryofDefaultServeMux

    Callhttp.ListenAndServe(":9090",nil)1. InstantiateServer2. CallListenAndServemethodofServer3. Callnet.Listen("tcp",addr)tolistentoport4. Startaloopandacceptrequestsintheloopbody5. InstantiateaConnandstartagoroutineforeveryrequest:goc.serve()6. Readrequestdata:w,err:=c.readRequest()7. Checkwhetherhandlerisemptyornot,ifit'semptythenuseDefaultServeMux8. CallServeHTTPofhandler9. ExecutecodeinDefaultServeMuxinthiscase

    10. ChoosehandlerbyURLandexecutecodeinthathandlerfunction:mux.handler.ServeHTTP(w,r)11. Howtochoosehandler:A.CheckrouterrulesforthisURLB.CallServeHTTPinthathandlerifthereisoneC.Call

    ServeHTTPofNotFoundHandlerotherwise

    DirectoryPrevioussection:HowGoworkswithwebNextsection:Summary

    Links

  • Inthischapter,weintroducedHTTP,DNSresolutionflowandhowtobuildasimplewebserver.ThenwetalkedabouthowGoimplementswebserversforusbylookingatthesourcecodeofthenet/httppackage.

    Ihopethatyounowknowmuchmoreaboutwebdevelopment,andyoushouldseethatit'squiteeasyandflexibletobuildawebapplicationinGo.

    DirectoryPrevioussection:GetintohttppackageNextchapter:Userform

    3.5Summary

    Links

  • Auserformissomethingthatisverycommonlyusedwhendeveloppingwebapplications.Itprovidestheabilitytocommunicatebetweenclientsandservers.Youmustbeveryfamiliarwithformsifyouareawebdeveloper;ifyouareaC/C++programmer,youmaywanttoask:whatisauserform?

    Aformisanareathatcontainsformelements.Userscaninputinformationintoformelementsliketextboxes,dropdownlists,radiobuttons,checkboxes,etc.Weusetheformtagtodefineforms.

    ...inputelements...

    Goalreadyhasmanyconvenientfunctionstodealwithuserforms.YoucaneasilygetformdatainHTTPrequests,andtheyareeasytointegrateintoyourownwebapplications.Insection4.1,wearegoingtotalkabouthowtohandleformdatainGo.Also,sinceyoucannottrustanydatacomingfromtheclientside,youmustfirstverifythedatabeforeusingit.We'llgothroughsomeexamplesabouthowtoverifyformdatainsection4.2.

    WesaythatHTTPisstateless.Howcanweidentifythatcertainformsarefromthesameuser?Andhowdowemakesurethatoneformcanonlybesubmittedonce?We'lllookatsomedetailsconcerningcookies(acookieisinformationthatcanbesavedontheclientsideandaddedtotherequestheaderwhentherequestissenttotheserver)inbothsections4.3and4.4.

    Anotherbiguse-caseofformsisuploadingfiles.Insection4.5,youwilllearnhowtodothisaswellascontrollingthefileuploadsizebeforeitbeginsuploading,inGo.

    DirectoryPreviouschapter:Chapter3SummaryNextsection:Processforminputs

    4Userform

    Links

  • Beforewebegin,let'stakealookatasimpleexampleofatypicaluserform,savedaslogin.gtplinyourprojectfolder.

    Username:Password:

    Thisformwillsubmitto/loginontheserver.Aftertheuserclickstheloginbutton,thedatawillbesenttotheloginhandlerregisteredbytheserverrouter.ThenweneedtoknowwhetheritusesthePOSTmethodorGET.

    Thisiseasytofindoutusingthehttppackage.Let'sseehowtohandletheformdataontheloginpage.

    packagemain

    import("fmt""html/template""log""net/http""strings")

    funcsayhelloName(whttp.ResponseWriter,r*http.Request){r.ParseForm()//Parseurlparameterspassed,thenparsetheresponsepacketforthePOSTbody(requestbody)//attention:IfyoudonotcallParseFormmethod,thefollowingdatacannotbeobtainedformfmt.Println(r.Form)//printinformationonserverside.fmt.Println("path",r.URL.Path)fmt.Println("scheme",r.URL.Scheme)fmt.Println(r.Form["url_long"])fork,v:=ranger.Form{fmt.Println("key:",k)fmt.Println("val:",strings.Join(v,""))}fmt.Fprintf(w,"Helloastaxie!")//writedatatoresponse}

    funclogin(whttp.ResponseWriter,r*http.Request){fmt.Println("method:",r.Method)//getrequestmethodifr.Method=="GET"{t,_:=template.ParseFiles("login.gtpl")t.Execute(w,nil)}else{r.ParseForm()//logicpartofloginfmt.Println("username:",r.Form["username"])fmt.Println("password:",r.Form["password"])}}

    funcmain(){http.HandleFunc("/",sayhelloName)//settingrouterrulehttp.HandleFunc("/login",login)err:=http.ListenAndServe(":9090",nil)//settinglisteningportiferr!=nil{log.Fatal("ListenAndServe:",err)}}

    Hereweuser.Methodtogettherequestmethod,anditreturnsanhttpverb-"GET","POST","PUT",etc.

    4.1Processforminputs

  • Intheloginfunction,weuser.Methodtocheckwhetherit'saloginpageorloginprocessinglogic.Inotherwords,wechecktoseewhethertheuserissimplyopeningthepage,ortryingtologin.ServeshowsthepageonlywhentherequestcomesinviatheGETmethod,anditexecutestheloginlogicwhentherequestusesthePOSTmethod.

    Youshouldseethefollowinginterfaceafteropeninghttp://127.0.0.1:9090/logininyourbrowser.

    Figure4.1Userlogininterface

    Theserverwillnotprintanythinguntilafterwetypeinausernameandpassword,becausethehandlerdoesn'tparsetheformuntilwecallr.ParseForm().Let'saddr.ParseForm()beforefmt.Println("username:",r.Form["username"]),compileourprogramandtestitagain.Youwillfindthattheinformationisprintedontheserversidenow.

    r.Formcontainsalloftherequestarguments,forinstancethequery-stringintheURLandthedatainPOSTandPUT.Ifthedatahasconflicts,forexampleparametersthathavethesamename,theserverwillsavethedataintoaslicewithmultiplevalues.TheGodocumentationstatesthatGowillsavethedatafromGETandPOSTrequestsindifferentplaces.

    Trychangingthevalueoftheactionintheformhttp://127.0.0.1:9090/logintohttp://127.0.0.1:9090/login?username=astaxieinthelogin.gtplfile,testitagain,andyouwillseethatthesliceisprintedontheserverside.

    Figure4.2Serverprintsrequestdata

    Thetypeofrequest.Formisurl.Value.Itsavesdatawiththeformatkey=value.

    v:=url.Values{}v.Set("name","Ava")v.Add("friend","Jess")v.Add("friend","Sarah")v.Add("friend","Zoe")//v.Encode()=="name=Ava&friend=Jess&friend=Sarah&friend=Zoe"fmt.Println(v.Get("name"))fmt.Println(v.Get("friend"))fmt.Println(v["friend"])

    TipsRequestshavetheabilitytoaccessformdatausingtheFormValue()method.Forexample,youcanchanger.Form["username"]tor.FormValue("username"),andGocallsr.ParseFormautomatically.Noticethatitreturnsthefirstvalueifthereareargumentswiththesamename,anditreturnsanemptystringifthereisnosuchargument.

    DirectoryPrevioussection:UserformNextsection:Verificationofinputs

    Links

  • Oneofthemostimportantprinciplesinwebdevelopmentisthatyoucannottrustanythingfromclientsideuserforms.Youhavetoverifyallincomingdatabeforeuseit.Manywebsitesareaffectedbythisproblem,whichissimpleyetcrucial.

    Therearetwowaysofverifyformdatathatarecommonlyused.OneisJavaScriptverificationinthefront-end,andtheotherisserververificationintheback-end.Inthissection,wearegoingtotalkaboutserversideverificationinwebdevelopment.

    Sometimeswerequirethatusersinputsomefieldsbuttheydon't,forexampleintheprevioussectionwhenwerequiredausername.Youcanusethelenfunctiontogetthelengthofafieldinordertoensurethatusershaveenteredthisinformation.

    iflen(r.Form["username"][0])==0{//codeforemptyfield}

    r.Formtreatsdifferentformelementtypesdifferentlywhentheyareblank.Foremptytextboxes,textareasandfileuploads,itreturnsanemptystring;forradiobuttonsandcheckboxes,itdoesn'tevencreatethecorrespondingitems.Instead,youwillgeterrorsifyoutrytoaccessit.Therefore,it'ssafertouser.Form.Get()togetfiledvaluessinceitwillalwaysreturnemptyifthevaluedoesnotexist.Ontheotherhand,r.Form.Get()canonlygetonefieldvalueatatime,soyouneedtouser.Formtogetthemapofvalues.

    Sometimesyouonlyneednumbersforthefieldvalue.Forexample,let'ssaythatyourequiretheageofauserinintegerformonly,i.e50or10,insteadof"oldenough"or"youngman".Ifwerequireapositivenumber,wecanconvertthevaluetotheinttypefirst,thenprocessit.

    getint,err:=strconv.Atoi(r.Form.Get("age"))iferr!=nil{//erroroccurswhenconverttonumber,itmaynotanumber}

    //checkrangeofnumberifgetint>100{//toobig}

    Anotherwaytodothisisusingregularexpressions.

    ifm,_:=regexp.MatchString("^[0-9]+$",r.Form.Get("age"));!m{returnfalse}

    Forhighperformancepurposes,regularexpressionsarenotefficient,howeversimpleregularexpressionsareusuallyfastenough.Ifyouarefamiliarwithregularexpressions,it'saveryconvenientwaytoverifydata.NoticethatGousesRE2,soallUTF-8charactersaresupported.

    4.2Verificationofinputs

    Requiredfields

    Numbers

    Chinese

  • SometimesweneeduserstoinputtheirChinesenamesandwehavetoverifythattheyalluseChineseratherthanrandomcharacters.ForChineseverification,regularexpressionsaretheonlyway.

    ifm,_:=regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$",r.Form.Get("realname"));!m{returnfalse}

    SometimesweneeduserstoinputonlyEnglishletters.Forexample,werequiresomeone'sEnglishname,likeastaxieinsteadofasta.Wecaneasilyuseregularexpressionstoperformourverification.

    ifm,_:=regexp.MatchString("^[a-zA-Z]+$",r.Form.Get("engname"));!m{returnfalse}

    IfyouwanttoknowwhetherusershaveenteredvalidE-mailaddresses,youcanusethefollowingregularexpression:

    ifm,_:=regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`,r.Form.Get("email"));!m{fmt.Println("no")}else{fmt.Println("yes")}

    Let'ssaywerequireanitemfromourdropdownlist,butinsteadwegetavaluefabricatedbyhackers.Howdowepreventthisfromhappening?

    Supposewehavethefollowing:

    applepearbanana

    Wecanusethefollowingstrategytosanitizeourinput:

    slice:=[]string{"apple","pear","banana"}

    for_,v:=rangeslice{ifv==r.Form.Get("fruit"){returntrue}}returnfalse

    AllthefunctionsI'veshownaboveareinmyopensourceprojectforoperatingonslicesandmaps:https://github.com/astaxie/beeku

    Englishletters

    E-mailaddress

    Dropdownlist

  • Ifwewanttoknowwhethertheuserismaleorfemale,wemayusearadiobutton,returning1formaleand2forfemale.However,somelittlekidwhojustreadhisfirstbookonHTTP,decidestosendtoyoua3.Willyourprogramhavehaveexception?Asyoucansee,weneedtousethesamemethodaswedidforourdropdownlisttomakesurethatonlyexpectedvaluesarereturnedbyourradiobutton.

    MaleFemale

    Andweusefollowingcodetoverifytheinput:

    slice:=[]int{1,2}

    for_,v:=rangeslice{ifv==r.Form.Get("gender"){returntrue}}returnfalse

    Supposetherearesomecheckboxesforuserinterests,andthatyoudon'twantextraneousvalueshereeither.

    FootballBasketballTennis

    Inthiscase,thesanitizationisalittlebitdifferentthanverifyingthebuttonandcheckboxinputssinceherewegetaslicefromthecheckboxes.

    slice:=[]string{"football","basketball","tennis"}a:=Slice_diff(r.Form["interest"],slice)ifa==nil{returntrue}

    returnfalse

    Supposeyouwantuserstoinputvaliddatesortimes.Gohasthetimepackageforconvertingyear,monthanddaytotheircorrespondingtimes.Afterthat,it'seasytocheckit.

    t:=time.Date(2009,time.November,10,23,0,0,0,time.UTC)fmt.Printf("Golaunchedat%s\n",t.Local())

    Afteryouhavethetime,youcanusethetimepackageformoreoperations,dependingonyourneeds.

    Inthissection,we'vediscussedsomecommonmethodsforverifyingformdataserverside.IhopethatyounowunderstandmoreaboutdataverificationinGo,especiallyhowtouseregularexpressionstoyouradvantage.

    Radiobuttons

    Checkboxes

    Dateandtime

  • DirectoryPrevioussection:ProcessforminputsNextsection:Crosssitescripting

    Links

  • Today'swebsiteshavemuchmoredynamiccontentinordertoimproveuserexperience,whichmeansthatwemustprovidedynamicinformationdependingoneveryindividual'sbehavior.Unfortunately,thereisathingcalled"Crosssitescripting"(knownas"XSS")alwaysattackingdynamicwebsites,fromwhichstaticwebsitesarecompletelyfineatthistime.

    AttackersofteninjectmaliciousscriptslikeJavaScript,VBScript,ActiveXorFlashintothosewebsitesthathaveloopholes.Oncetheyhavesuccessfullyinjectedtheirscripts,userinformationcanbestolenandyourwebsitecanbefloodedwithspam.Theattackerscanalsochangeusersettingstowhatevertheywant.

    Ifyouwanttopreventthiskindofattack,youshouldcombinethetwofollowingapproaches:

    Verificationofalldatafromusers,whichwetalkedaboutintheprevioussection.Carefullyhandledatathatwillbesenttoclientsinordertopreventanyinjectedscriptsfromrunningonbrowsers.

    SohowcanwedothesetwothingsinGo?Fortunately,thehtml/templatepackagehassomeusefulfunctionstoescapedataasfollows:

    funcHTMLEscape(wio.Writer,b[]byte)escapesbtow.funcHTMLEscapeString(sstring)stringreturnsastringafterescapingfroms.funcHTMLEscaper(args...interface{})stringreturnsastringafterescapingfrommultiplearguments.

    Let'schangetheexampleinsection4.1:

    fmt.Println("username:",template.HTMLEscapeString(r.Form.Get("username")))//printatserversidefmt.Println("password:",template.HTMLEscapeString(r.Form.Get("password")))template.HTMLEscape(w,[]byte(r.Form.Get("username")))//respondedtoclients

    Ifsomeonetriestoinputtheusernameasalert(),wewillseethefollowingcontentinthebrowser:

    Figure4.3JavaScriptafterescaped

    Functionsinthehtml/templatepackagehelpyoutoescapeallHTMLtags.Whatifyoujustwanttoprintalert()tobrowsers?Youshouldusetext/templateinstead.

    import"text/template"...t,err:=template.New("foo").Parse(`{{define"T"}}Hello,{{.}}!{{end}}`)err=t.ExecuteTemplate(out,"T","alert('youhavebeenpwned')")

    Output:

    Hello,alert('youhavebeenpwned')!

    Oryoucanusethetemplate.HTMLtype:Variablecontentwillnotbeescapedifitstypeistemplate.HTML.

    import"html/template"...t,err:=template.New("foo").Parse(`{{define"T"}}Hello,{{.}}!{{end}}`)err=t.ExecuteTemplate(out,"T",template.HTML("alert('youhavebeenpwned')"))

    Output:

    4.3Crosssitescripting

  • Hello,alert('youhavebeenpwned')!

    Onemoreexampleofescaping:

    import"html/template"...t,err:=template.New("foo").Parse(`{{define"T"}}Hello,{{.}}!{{end}}`)err=t.ExecuteTemplate(out,"T","alert('youhavebeenpwned')")

    Output:

    Hello,!

    DirectoryPrevioussection:VerificationofinputsNextsection:Duplicatesubmissions

    Links

  • Idon'tknowifyou'veeverseensomeblogsorBBS'thathavemorethanonepoststhatareexactlythesame,butIcantellyouthatit'sbecauseuserssubmittedduplicatepostforms.Theremanythingsthatcancauseduplicatesubmissions;sometimesusersjustdoubleclickthesubmitbutton,ortheywanttomodifysomecontentafterpostingandpressthebackbutton.Othertimesit'stheintentionalactionsofmalicioususers.It'seasytoseehowduplicatesubmissionscanleadtomanyproblems.Thus,wehavetouseeffectivemeanstopreventit.

    Thesolutionistoaddahiddenfieldwithauniquetokentoyourform,andtoalwayscheckthistokenbeforeprocessingtheincomingdata.Also,ifyouareusingAjaxtosubmitaform,useJavaScripttodisablethesubmitbuttononcetheformhasbeensubmitted.

    Let'simprovetheexamplefromsection4.2:

    FootballBasketballTennisUsername:Password:

    WeuseanMD5hash(timestamp)togeneratethetoken,andaddedittobothahiddenfieldontheclientsideformandasessioncookieontheserverside(Chapter6).Wecanthenusethistokentocheckwhetherornotthisformwassubmitted.

    funclogin(whttp.ResponseWriter,r*http.Request){fmt.Println("method:",r.Method)//getrequestmethodifr.Method=="GET"{crutime:=time.Now().Unix()h:=md5.New()io.WriteString(h,strconv.FormatInt(crutime,10))token:=fmt.Sprintf("%x",h.Sum(nil))

    t,_:=template.ParseFiles("login.gtpl")t.Execute(w,token)}else{//loginrequestr.ParseForm()token:=r.Form.Get("token")iftoken!=""{//checktokenvalidity}else{//giveerrorifnotoken}fmt.Println("usernamelength:",len(r.Form["username"][0]))fmt.Println("username:",template.HTMLEscapeString(r.Form.Get("username")))//printinserversidefmt.Println("password:",template.HTMLEscapeString(r.Form.Get("password")))template.HTMLEscape(w,[]byte(r.Form.Get("username")))//respondtoclient}}

    Figure4.4Thecontentinbrowserafteraddingatoken

    Youcanrefreshthispageandyouwillseeadifferenttokeneverytime.Thisensuresthateveryformisunique.

    Fornow,youcanpreventmanyduplicatesubmissionattacksbyaddingtokenstoyourforms,butitcannotpreventalldeceptiveattacksofthistype.Thereismuchmoreworkthatneedstobedone.

    4.4Duplicatesubmissions

    Links

  • DirectoryPrevioussection:CrosssitescriptingNextsection:Fileupload

  • SupposeyouhaveawebsitelikeInstagramandyouwantuserstouploadtheirbeautifulphotos.Howwouldyouimplementthatfunctionality?

    Youhavetoaddpropertyenctypetotheformthatyouwanttouseforuploadingphotos.Therearethreepossiblevaluesforthisproperty:

    application/x-www-form-urlencodedTranscodeallcharactersbeforeuploading(default).multipart/form-dataNotranscoding.Youmustusethisvaluewhenyourformhasfileuploadcontrols.text/plainConvertspacesto"+",butnotranscodingforspecialcharacters.

    Therefore,theHTMLcontentofafileuploadformshouldlooklikethis:

    Uploadfile

    Weneedtoaddafunctionontheserversidetohandlethisform.

    http.HandleFunc("/upload",upload)

    //uploadlogicfuncupload(whttp.ResponseWriter,r*http.Request){fmt.Println("method:",r.Method)ifr.Method=="GET"{crutime:=time.Now().Unix()h:=md5.New()io.WriteString(h,strconv.FormatInt(crutime,10))token:=fmt.Sprintf("%x",h.Sum(nil))

    t,_:=template.ParseFiles("upload.gtpl")t.Execute(w,token)}else{r.ParseMultipartForm(32

  • useio.Copytosavetoyourfilesystem.

    Youdon'tneedtocallr.ParseFormwhenyouaccessothernon-filefieldsintheformbecauseGowillcallitwhenit'snecessary.Also,callingParseMultipartFormonceisenough-multiplecallsmakenodifference.

    Weusethreestepsforuploadingfilesasfollows:

    1. Addenctype="multipart/form-data"toyourform.2. Callr.ParseMultipartFormontheserversidetosavethefileeithertomemoryortoatemporaryfile.3. Callr.FormFiletogetthefilehandleandsavetothefilesystem.

    Thefilehandleristhemultipart.FileHeader.Itusesthefollowingstruct:

    typeFileHeaderstruct{FilenamestringHeadertextproto.MIMEHeader//containsfilteredorunexportedfields}

    Figure4.5Printinformationonserverafterreceivingfile.

    Ishowedanexampleofusingaformtoauploadafile.WecanimpersonateaclientformtouploadfilesinGoaswell.

    packagemain

    import("bytes""fmt""io""io/ioutil""mime/multipart""net/http""os")

    funcpostFile(filenamestring,targetUrlstring)error{bodyBuf:=&bytes.Buffer{}bodyWriter:=multipart.NewWriter(bodyBuf)

    //thisstepisveryimportantfileWriter,err:=bodyWriter.CreateFormFile("uploadfile",filename)iferr!=nil{fmt.Println("errorwritingtobuffer")returnerr}

    //openfilehandlefh,err:=os.Open(filename)iferr!=nil{fmt.Println("erroropeningfile")returnerr}

    //iocopy_,err=io.Copy(fileWriter,fh)iferr!=nil{returnerr}

    contentType:=bodyWriter.FormDataContentType()bodyWriter.Close()

    resp,err:=http.Post(targetUrl,contentType,bodyBuf)iferr!=nil{returnerr

    Clientsuploadfiles

  • }deferresp.Body.Close()resp_body,err:=ioutil.ReadAll(resp.Body)iferr!=nil{returnerr}fmt.Println(resp.Status)fmt.Println(string(resp_body))returnnil}

    //sampleusagefuncmain(){target_url:="http://localhost:9090/upload"filename:="./astaxie.pdf"postFile(filename,target_url)}

    Theaboveexampleshowsyouhowtouseaclienttouploadfiles.Itusesmultipart.WritetowritefilesintocacheandsendsthemtotheserverthroughthePOSTmethod.

    Ifyouhaveotherfieldsthatneedtowriteintodata,likeusername,callmultipart.WriteFieldasneeded.

    DirectoryPrevioussection:DuplicatesubmissionsNextsection:Summary

    Links

  • Inthischapter,wemainlylearnedhowtoprocessformdatainGothroughseveralexampleslikelogginginusersanduploadingfiles.Wealsoemphasizedthatverifyinguserdataisextremelyimportantforwebsitesecurity,andweusedonesectiontotalkabouthowtofilterdatawithregularexpressions.

    Ihopethatyounowknowmoreaboutthecommunicationprocessbetweenclientandserver.

    DirectoryPrevioussection:FileuploadNextchapter:Database

    4.6Summary

    Links

  • Forwebdevelopers,thedatabaseisatthecoreofwebdevelopment.Youcansavealmostanythingintoadatabaseandqueryorupdatedatainsideit,likeuserinformation,productsornewsarticles.

    Godoesn'tprovideanydatabasedrivers,butitdoeshaveadriverinterfacedefinedinthedatabase/sqlpackage.Peoplecandevelopdatabasedriversbasedonthatinterface.Insection5.1,wearegoingtotalkaboutdatabasedriverinterfacedesigninGo;insections5.2to5.4,IwillintroducesomeSQLdatabasedriverstoyou;insection5.5,i'llpresenttheORMthati'vedevelopedwhichisbasedonthedatabase/sqlinterfacestandard.It'scompatiblewithmostdriversthathaveimplementedthedatabase/sqlinterface,anditmakesiteasytoaccessdatabasesidiomaticallyinGo.

    NoSQLhasbeenahottopicinrecentyears.MorewebsitesaredecidingtouseNoSQLdatabasesastheirmaindatabaseinsteadofjustforthepurposeofcaching.IwillintroduceyoutotwoNoSQLdatabases,whichareMongoDBandRedis,insection5.6.

    DirectoryPreviousChapter:Chapter4SummaryNextsection:database/sqlinterface

    5Database

    Links

  • Godoesn'tprovideanyofficialdatabasedrivers,unlikeotherlanguageslikePHPwhichdo.However,itdoeshavesomedatabasedriverinterfacestandardsfordeveloperstodevelopdatabasedriverswith.Theadvantageisthatifyourcodeisdevelopedaccordingtotheseinterfacestandards,youwillnotneedtochangeanycodeifyourdatabasechanges.Let'sseewhatthesedatabaseinterfacestandardsare.

    Thisfunctionisinthedatabase/sqlpackageforregisteringdatabasedriverswhenyouusethird-partydatabasedrivers.AlloftheseshouldcalltheRegister(namestring,driverdriver.Driver)functionininit()inordertoregisterthemselves.

    Let'stakealookatthecorrespondingmymysqlandsqlite3drivercode:

    //https://github.com/mattn/go-sqlite3driverfuncinit(){sql.Register("sqlite3",&SQLiteDriver{})}

    //https://github.com/mikespook/mymysqldriver//Driverautomaticallyregisteredindatabase/sqlvard=Driver{proto:"tcp",raddr:"127.0.0.1:3306"}funcinit(){Register("SETNAMESutf8")sql.Register("mymysql",&d)}

    Weseethatallthird-partydatabasedrivershaveimplementedthisfunctiontoregisterthemselves,andGousesamaptosaveuserdriversinsideofdatabse/sql.

    vardrivers=make(map[string]driver.Driver)

    drivers[name]=driver

    Therefore,thisregisterfunctioncanregisterdriversasmanyasyouwantwithdifferentnames.

    Wealwaysseethefollowingcodewhenweusethird-partydrivers:

    import("database/sql"_"github.com/mattn/go-sqlite3")

    Heretheunderscore(alsoknownasa'blank')_canbequiteconfusingformanybeginners,butthisisagreatfeatureinGo.Wealreadyknowthatthisidentifierisfordiscardingvaluesfromfunctionreturns,andalsothatyoumustuseallpackagesthatyou'veimportedinyourcodeinGo.Sowhentheblankisusedwithimport,itmeansthatyouneedtoexecutetheinit()functionofthatpackagewithoutdirectlyusingit,whichexactlyfitstheuse-caseforregisteringdatabasedrivers.

    DriverisaninterfacecontaininganOpen(namestring)methodthatreturnsaConninterface.

    typeDriverinterface{

    5.1database/sqlinterface

    sql.Register

    driver.Driver

  • Open(namestring)(Conn,error)}

    Thisisaone-timeConn,whichmeansitcanonlybeusedonceinonegoroutine.Thefollowingcodewillcauseerrorstooccur:

    ...gogoroutineA(Conn)//querygogoroutineB(Conn)//insert...

    BecauseGohasnoideawhichgoroutinedoeswhatoperation,thequeryoperationmaygettheresultoftheinsertoperation,andvice-versa.

    Allthird-partydriversshouldhavethisfunctiontoparsethenameofConnandreturnthecorrectresults.

    Thisisadatabaseconnectioninterfacewithsomemethods,andasi'vesaidabove,thesameConncanonlybeusedinonegoroutine.

    typeConninterface{Prepare(querystring)(Stmt,error)Close()errorBegin()(Tx,error)}

    PreparereturnsthepreparestatusofcorrespondingSQLcommandsforqueryinganddeleting,etc.Closeclosesthecurrentconnectionandcleansresources.Mostthird-partydriversimplementsomekindofconnectionpool,soyoudon'tneedtocacheconnectionsunlessyouwanttohaveunexpectederrors.BeginreturnsaTxthatrepresentsatransactionhandle.Youcanuseitforquerying,updating,rollingbacktransactions,etc.

    ThisisareadystatusthatcorrespondswithConn,soitcanonlybeusedinonegoroutinelikeConn.

    typeStmtinterface{Close()errorNumInput()intExec(args[]Value)(Result,error)Query(args[]Value)(Rows,error)}

    Closeclosesthecurrentconnectionbutstillreturnsrowdataifitisexecutingaqueryoperation.NumInputreturnsthenumberofobligatearguments.Databasedriversshouldchecktheircaller'sargumentswhentheresultisgreaterthan0,anditreturns-1whendatabasedriversdon'tknowanyobligateargument.Execexecutestheupdate/insertSQLcommandspreparedinPrepare,returnsResult.QueryexecutestheselectSQLcommandpreparedinPrepare,returnsrowdata.

    Generally,transactionhandlesonlyhavesubmitorrollbackmethods,anddatabasedriversonlyneedtoimplementthesetwomethods.

    driver.Conn

    driver.Stmt

    driver.Tx

  • typeTxinterface{Commit()errorRollback()error}

    Thisisanoptionalinterface.

    typeExecerinterface{Exec(querystring,args[]Value)(Result,error)}

    Ifthedriverdoesn'timplementthisinterface,whenyoucallDB.Exec,itwillautomaticallycallPrepare,thenreturnStmt.AfterthatitexecutestheExecmethodofStmt,thenclosesStmt.

    Thisistheinterfaceforresultsofupdate/insertoperations.

    typeResultinterface{LastInsertId()(int64,error)RowsAffected()(int64,error)}

    LastInsertIdreturnsauto-incrementIdnumberafteradatabaseinsertoperation.RowsAffectedreturnsrowsthatwereaffectedbyqueryoperations.

    Thisistheinterfacefortheresultofaqueryoperation.

    typeRowsinterface{Columns()[]stringClose()errorNext(dest[]Value)error}

    Columnsreturnsfieldinformationofdatabasetables.Theslicehasaone-to-onecorrespondencewithSQLqueryfieldsonly,anddoesnotreturnallfieldsofthatdatabasetable.CloseclosesRowsiterator.Nextreturnsnextdataandassignstodest,convertingallstringsintobytearrays,andgetsio.EOFerrorifnomoredataisavailable.

    Thisisanaliasofint64,butitimplementstheResultinterface.

    typeRowsAffectedint64

    func(RowsAffected)LastInsertId()(int64,error)

    func(vRowsAffected)RowsAffected()(int64,error)

    driver.Execer

    driver.Result

    driver.Rows

    driver.RowsAffected

  • Thisisanemptyinterfacethatcancontainsanykindofdata.

    typeValueinterface{}

    TheValuemustbesomethingthatdriverscanoperateonornil,soitshouldbeoneoffollowingtypes:

    int64float64bool[]bytestring[*]ExceptRows.Nextwhichcannotreturnstringtime.Time

    Thisdefinesaninterfaceforconvertingnormalvaluestodriver.Value.

    typeValueConverterinterface{ConvertValue(vinterface{})(Value,error)}

    Thisinterfaceiscommonlyusedindatabasedriversandhasmanyusefulfeatures:

    Convertsdriver.Valuetoacorrespondingdatabasefieldtype,forexampleconvertsint64touint16.Convertsdatabasequeryresultstodriver.Value.Convertsdriver.Valuetoauserdefinedvalueinthescanfunction.

    Thisdefinesaninterfaceforreturningdriver.Value.

    typeValuerinterface{Value()(Value,error)}

    Manytypesimplementthisinterfaceforconversionbetweendriver.Valueanditself.

    Atthispoint,youshouldknowabitaboutdeveloppingdatabasedriversinGo.Onceyoucanimplementinterfacesforoperationslikeadd,delete,update,etc.,thereareonlyafewproblemsleftrelatedtocommunicatingwithspecificdatabases.

    databse/sqldefinesevenmorehigh-levelmethodsontopofdatabase/sql/driverformoreconvenientdatabaseoperations,anditsuggeststhatyouimplementaconnectionpool.

    typeDBstruct{driverdriver.Driver

    driver.Value

    driver.ValueConverter

    driver.Valuer

    database/sql

  • dsnstringmusync.Mutex//protectsfreeConnandclosedfreeConn[]driver.Connclosedbool}

    Asyoucansee,theOpenfunctionreturnsaDBthathasafreeConn,andthisisasimpleconnectionpool.Itsimplementationisverysimpleandugly.Itusesdeferdb.putConn(ci,err)intheDb.preparefunctiontoputaconnectionintotheconnectionpool.EverytimeyoucalltheConnfunction,itchecksthelengthoffreeCoon.Ifit'sgreaterthan0,thatmeansthereisareusableconnectionanditdirectlyreturnstoyou.Otherwiseitcreatesanewconnectionandreturns.

    DirectoryPrevioussection:DatabaseNextsection:MySQL

    Links

  • TheLAMPstackhasbeenverypopularontheinternetinrecentyears,andtheMinLAMPstandforMySQL.MySQLisfamousbecauseit'sopensourceandeasytouse.Assuch,itbecamethedefactodatabaseintheback-endsofmanywebsites.

    ThereareacoupleofdriversthatsupportMySQLinGo.Someofthemimplementthedatabase/sqlinterface,andothersusetheirowninterfacestandards.

    https://github.com/go-sql-driver/mysqlsupportsdatabase/sql,writteninpureGo.https://github.com/ziutek/mymysqlsupportsdatabase/sqlanduserdefinedinterfaces,writteninpureGo.https://github.com/Philio/GoMySQLonlysupportsuserdefinedinterfaces,writteninpureGo.

    I'llusethefirstdriverinthefollowingexamples(Iusethisoneinmypersonalprojectstoo),andIalsorecommendthatyouuseitforthefollowingreasons:

    It'sanewdatabasedriverandsupportsmorefeatures.Fullysupportsdatabse/sqlinterfacestandards.Supportskeepalive,longconnectionswiththread-safety.

    Inthefollowingsections,I'llusethesamedatabasetablestructurefordifferentdatabases,thencreateSQLasfollows:

    CREATETABLE`userinfo`(`uid`INT(10)NOTNULLAUTO_INCREMENT,`username`VARCHAR(64)NULLDEFAULTNULL,`departname`VARCHAR(64)NULLDEFAULTNULL,`created`DATENULLDEFAULTNULL,PRIMARYKEY(`uid`));

    Thefollowingexampleshowshowtooperateonadatabasebasedonthedatabase/sqlinterfacestandards.

    packagemain

    import(_"github.com/go-sql-driver/mysql""database/sql""fmt")

    funcmain(){db,err:=sql.Open("mysql","astaxie:astaxie@/test?charset=utf8")checkErr(err)

    //insertstmt,err:=db.Prepare("INSERTuserinfoSETusername=?,departname=?,created=?")checkErr(err)

    res,err:=stmt.Exec("astaxie","","2012-12-09")checkErr(err)

    id,err:=res.LastInsertId()checkErr(err)

    fmt.Println(id)//updatestmt,err=db.Prepare("updateuserinfosetusername=?whereuid=?")

    5.2MySQL

    MySQLdrivers

    Samples

  • checkErr(err)

    res,err=stmt.Exec("astaxieupdate",id)checkErr(err)

    affect,err:=res.RowsAffected()checkErr(err)

    fmt.Println(affect)

    //queryrows,err:=db.Query("SELECT*FROMuserinfo")checkErr(err)

    forrows.Next(){varuidintvarusernamestringvardepartmentstringvarcreatedstringerr=rows.Scan(&uid,&username,&department,&created)checkErr(err)fmt.Println(uid)fmt.Println(username)fmt.Println(department)fmt.Println(created)}

    //deletestmt,err=db.Prepare("deletefromuserinfowhereuid=?")checkErr(err)

    res,err=stmt.Exec(id)checkErr(err)

    affect,err=res.RowsAffected()checkErr(err)

    fmt.Println(affect)

    db.Close()

    }

    funccheckErr(errerror){iferr!=nil{panic(err)}}

    Letmeexplainafewoftheimportantfunctionshere:

    sql.Open()opensaregistereddatabasedriver.TheGo-MySQL-Driverregisteredthemysqldriverhere.ThesecondargumentistheDSN(DataSourceName)thatdefinesinformationpertainingtothedatabaseconnection.Itsupportsfollowingformats:

    user@unix(/path/to/socket)/dbname?charset=utf8user:password@tcp(localhost:5555)/dbname?charset=utf8user:password@/dbnameuser:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname

    db.Prepare()returnsaSQLoperationthatisgoingtobeexecuted.ItalsoreturnstheexecutionstatusafterexecutingSQL.

    db.Query()executesSQLandreturnsaRowsresult.stmt.Exec()executesSQLthathasbeenpreparedandstoredinStmt.

    Notethatweusetheformat=?topassarguments.ThisisnecessaryforpreventingSQLinjectionattacks.

    Links

  • DirectoryPrevioussection:database/sqlinterfaceNextsection:SQLite

  • SQLiteisanopensource,embeddedrelationaldatabase.Ithasaself-contained,zero-configurationandtransaction-supporteddatabaseengine.Itscharacteristicsarehighlyportable,easytouse,compact,efficientandreliable.Inmostofcases,youonlyneedabinaryfileofSQLitetocreate,connectandoperateadatabase.Ifyouarelookingforanembeddeddatabasesolution,SQLiteisworthconsidering.YoucansaySQLiteistheopensourceversionofAccess.

    TherearemanydatabasedriversforSQLiteinGo,butmanyofthemdonotsupportthedatabase/sqlinterfacestandards.

    https://github.com/mattn/go-sqlite3supportsdatabase/sql,basedoncgo.https://github.com/feyeleanor/gosqlite3doesn'tsupportdatabase/sql,basedoncgo.https://github.com/phf/go-sqlite3doesn'tsupportdatabase/sql,basedoncgo.

    Thefirstdriveristheonlyonethatsupportsthedatabase/sqlinterfacestandardinitsSQLitedriver,soIusethisinmyprojects-itwillmakeiteasytomigratemycodeinthefutureifIneedto.

    WecreatethefollowingSQL:

    CREATETABLE`userinfo`(`uid`INTEGERPRIMARYKEYAUTOINCREMENT,`username`VARCHAR(64)NULL,`departname`VARCHAR(64)NULL,`created`DATENULL);

    Anexample:

    packagemain

    import("database/sql""fmt"_"github.com/mattn/go-sqlite3")

    funcmain(){db,err:=sql.Open("sqlite3","./foo.db")checkErr(err)

    //insertstmt,err:=db.Prepare("INSERTINTOuserinfo(username,departname,created)values(?,?,?)")checkErr(err)

    res,err:=stmt.Exec("astaxie","","2012-12-09")checkErr(err)

    id,err:=res.LastInsertId()checkErr(err)

    fmt.Println(id)//updatestmt,err=db.Prepare("updateuserinfosetusername=?whereuid=?")checkErr(err)

    res,err=stmt.Exec("astaxieupdate",id)checkErr(err)

    affect,err:=res.RowsAffected()checkErr(err)

    5.3SQLite

    SQLitedrivers

    Samples

  • fmt.Println(affect)

    //queryrows,err:=db.Query("SELECT*FROMuserinfo")checkErr(err)

    forrows.Next(){varuidintvarusernamestringvardepartmentstringvarcreatedstringerr=rows.Scan(&uid,&username,&department,&created)checkErr(err)fmt.Println(uid)fmt.Println(username)fmt.Println(department)fmt.Println(created)}

    //deletestmt,err=db.Prepare("deletefromuserinfowhereuid=?")checkErr(err)

    res,err=stmt.Exec(id)checkErr(err)

    affect,err=res.RowsAffected()checkErr(err)

    fmt.Println(affect)

    db.Close()

    }

    funccheckErr(errerror){iferr!=nil{panic(err)}}

    Youmayhavenoticedthatthecodeisalmostthesameasintheprevioussection,andthatweonlychangedthenameoftheregistereddriverandcalledsql.OpentoconnecttoSQLiteinadifferentway.

    Asafinalnoteonthissecton,thereisausefulSQLitemanagementtoolavailable:http://sqliteadmin.orbmu2k.de/

    DirectoryPrevioussection:MySQLNextsection:PostgreSQL

    Links

  • PostgreSQLisanobject-relationaldatabasemanagementsystemavailableformanyplatformsincludingLinux,FreeBSD,Solaris,MicrosoftWindowsandMacOSX.ItisreleasedunderanMIT-stylelicense,andisthusfreeandopensourcesoftware.It'slargerthanMySQLbecauseit'sdesignedforenterpriseusagelikeOracle.Postgresqlisgoodchoiceforenterprisetypeprojects.

    TherearemanydatabasedriversavailableforPostgreSQL.Herearethreeexamplesofthem:

    https://github.com/bmizerany/pqsupportsdatabase/sql,writteninpureGo.https://github.com/jbarham/gopgsqldriversupportsdatabase/sql,writteninpureGo.https://github.com/lxn/go-pgsqlsupportsdatabase/sql,writteninpureGo.

    I'llusethefirstoneinmyfollowingexamples.

    WecreatethefollowingSQL:

    CREATETABLEuserinfo(uidserialNOTNULL,usernamecharactervarying(100)NOTNULL,departnamecharactervarying(500)NOTNULL,Createddate,CONSTRAINTuserinfo_pkeyPRIMARYKEY(uid))WITH(OIDS=FALSE);

    Anexample:

    packagemain

    import("database/sql""fmt"_"github.com/lib/pq""time")

    const(DB_USER="postgres"DB_PASSWORD="postgres"DB_NAME="test")

    funcmain(){dbinfo:=fmt.Sprintf("user=%spassword=%sdbname=%ssslmode=disable",DB_USER,DB_PASSWORD,DB_NAME)db,err:=sql.Open("postgres",dbinfo)checkErr(err)deferdb.Close()

    fmt.Println("#Insertingvalues")

    varlastInsertIdinterr=db.QueryRow("INSERTINTOuserinfo(username,departname,created)VALUES($1,$2,$3)returninguid;","astaxie","","2012-12-09").Scan(&lastInsertId)checkErr(err)fmt.Println("lastinsertedid=",lastInsertId)

    fmt.Println("#Updating")

    5.4PostgreSQL

    PostgreSQLdrivers

    Samples

  • stmt,err:=db.Prepare("updateuserinfosetusername=$1whereuid=$2")checkErr(err)

    res,err:=stmt.Exec("astaxieupdate",lastInsertId)checkErr(err)

    affect,err:=res.RowsAffected()checkErr(err)

    fmt.Println(affect,"rowschanged")

    fmt.Println("#Querying")rows,err:=db.Query("SELECT*FROMuserinfo")checkErr(err)

    forrows.Next(){varuidintvarusernamestringvardepartmentstringvarcreatedtime.Timeerr=rows.Scan(&uid,&username,&department,&created)checkErr(err)fmt.Println("uid|username|department|created")fmt.Printf("%3v|%8v|%6v|%6v\n",uid,username,department,created)}

    fmt.Println("#Deleting")stmt,err=db.Prepare("deletefromuserinfowhereuid=$1")checkErr(err)

    res,err=stmt.Exec(lastInsertId)checkErr(err)

    affect,err=res.RowsAffected()checkErr(err)

    fmt.Println(affect,"rowschanged")}

    funccheckErr(errerror){iferr!=nil{panic(err)}}

    NotethatPostgreSQLusesthe$1,$2formatinsteadofthe?thatMySQLuses,andithasadifferentDSNformatinsql.Open.AnotherthingisthatthePostgresdriverdoesnotsupportsql.Result.LastInsertId().Soinsteadofthis,

    stmt,err:=db.Prepare("INSERTINTOuserinfo(username,departname,created)VALUES($1,$2,$3);")res,err:=stmt.Exec("astaxie","","2012-12-09")fmt.Println(res.LastInsertId())

    usedb.QueryRow()and.Scan()togetthevalueforthelastinsertedid.

    err=db.QueryRow("INSERTINTOTABLE_NAMEvalues($1)returninguid;",VALUE1").Scan(&lastInsertId)fmt.Println(lastInsertId)

    DirectoryPrevioussection:SQLiteNextsection:DevelopORMbasedonbeedb

    Links

  • (Projectbeedbisnolongermaintained,butthecodesstillthere)

    beedbisanORM(object-relationalmapper)developedinGo,byme.ItusesidiomaticGotooperateondatabases,implementingstructtodatabasemappingandactsasalightweightGoORMframework.ThepurposeofdevelopingthisORMisnotonlytohelppeoplelearnhowtowriteanORM,butalsotofindagoodbalancebetweenfunctionalityandperformancewhenitcomestodatapersistence.

    beedbisanopensourceprojectthatsupportsbasicORMfunctionality,butdoesn'tsupportassociationqueries.

    Becausebeedbsupportsdatabase/sqlinterfacestandards,anydriverthatimplementsthisinterfacecanbeusedwithbeedb.I'vetestedthefollowingdrivers:

    Mysql:github.com/ziutek/mymysql/godrv

    Mysql:code.google.com/p/go-mysql-driver

    PostgreSQL:github.com/bmizerany/pq

    SQLite:github.com/mattn/go-sqlite3

    MSADODB:github.com/mattn/go-adodb

    ODBC:bitbucket.org/miquella/mgodbc

    Youcanusegogettoinstallbeedblocally.

    gogetgithub.com/astaxie/beedb

    First,youhavetoimportallthenecessarypackages:

    import("database/sql""github.com/astaxie/beedb"_"github.com/ziutek/mymysql/godrv")

    Thenyouneedtoopenadatabaseconnectionandcreateabeedbobject(MySQLinthisexample):

    db,err:=sql.Open("mymysql","test/xiemengjun/123456")iferr!=nil{panic(err)}orm:=beedb.New(db)

    beedb.New()actuallyhastwoarguments.Thefirstisthethedatabaseobject,andthesecondisforindicatingwhichdatabaseengineyou'reusing.Ifyou'reusingMySQL/SQLite,youcanjustskipthesecondargument.

    5.5Develo