ถ้า Rails app ไม่บอกว่าใครมาเยี่ยม? ไม่รู้ว่า request 2 หน้ามาจากคนเดียวกัน? ข้อมูลที่เก็บหายทุก response?
อาจโอเคสำหรับ static site แต app ส่วนใหญ่ต้องเก็บ บาง data ของ user อาจเป็น user id, preferred language, หรือว่าอยากดู desktop version บน iPad เสมอ
session เหมาะสำหรับ data แบบนี้ ข้อมูลน้อยที่อยากเก็บเกิน 1 request
Sessions ใช้ง่าย:
session[:current_user_id] = @user.id
แตอาจ magical สิ่งที่ session คืออะไร Rails รู้ยังไงว่าโชว์ข้อมูลถูกคนถูก? และตัดสินใจเก็บ session data ที่ไหน?
Session คืออะไร?
Session คือที่เก็บข้อมูลระหว่าง request หนึ่ง ที่อ่านได้ใน requests ต่อไป
เซต data ใน controller action:
def create # ... session[:current_user_id] = @user.id # ... end
อ่านในอีก action:
def index current_user = User.find_by_id(session[:current_user_id]) # ... end
อาจไม่ ดู น่าสนใจ แตต้องการ coordination ระหว่าง browser และ Rails app และเริ่มจาก cookies
เวลา request webpage server ตั้ง cookie ตอน response:
~ jweiss$ curl -I https://www.google.com | grep Set-Cookie Set-Cookie: NID=67=J2xeyegolV0SSneukSOANOCoeuDQs7G1FDAK2j-nVyaoejz-4K6aouUQtyp5B_rK3Z7G-EwTIzDm7XQ3_ZUVNnFmlGfIHMAnZQNd4kM89VLzCsM0fZnr_N8-idASAfBEdS; expires=Wed, 16-Sep-2015 05:44:42 GMT; path=/; domain=.google.com; HttpOnly
Browser เก็บ cookies จนกว่า cookie จะหมดอายุ ทุก request browser ส่ง cookies กลับ server:
... > GET / HTTP/1.1 > User-Agent: curl/7.37.1 > Host: www.google.com > Accept: */* > Cookie: NID=67=J2xeyegolV0SSneukSOANOCoeuDQs7G1FDAK2j-nVyaoejz-4K6aouUQtyp5B_rK3Z7G-EwTIzDm7XQ3_ZUVNnFmlGfIHMAnZQNd4kM89VLzCsM0fZnr_N8-idASAfBEdS; expires=Wed, 16-Sep-2015 05:44:42 GMT; path=/; domain=.google.com; HttpOnly ...
Cookies เยอะดู gibberish และควรจะเป็น เพราะข้อมูลใน cookie ไม่ใช่ให้ user Rails app ควบคว่า cookie หมายถึงอะไร App ตั้งมัน App อ่านมัน
เกี่ยวกับ Session ยังไง?
มี cookie ใส่ data request หนึ่ง ออกมา request ถัดไป เหมือน session เหรอ?
Default ใน Rails ไม่ต่างมาก Rails ทำงานกับ cookie ให้ secure แตนอกนั้นทำงานเหมือนคาด ไอ้ data เข้า cookie data เดียวออกมา ถ้านี่เป็นทั้งหมด ไม่มีเหตุผลแยก sessions จาก cookies
แต cookies ไม่ใช่คำตอบเสมอไป:
เก็บได้ ~4kb ใน cookie
ปกติพอ แตบางครั้งไม่พอ
Cookies ส่งไปทุก request
Cookies ใหญ่ = requests/responses ใหญ่ = เว็บช้า
ถ้า
secret_key_baseleak users เปลี่ยน data ใน cookie ได้รวม
current_user_idใครก็เป็น user ไหนก็ได้!เก็บ data ผิดใน cookie ไม่ secure
ถ้าระวัง ไม่ใช่ปัญหาใหญ่
แตตอนไม่เก็บ session data ใน cookie ได้เพราะเหตุเหล่านี้ Rails มีที่อื่น:
Alternative Session Stores
Session stores ที่ ไม่ใช่ cookie session store ทำงานคล้ายกันหมด แตคิดง่ายกับ real example
ถ้าเก็บ sessions ด้วย ActiveRecord:
- ตอน
session[:current_user_id] = 1และ session ไม่มีอยู่: - Rails สร้าง record ใหม่ใน
sessionstable ด้วย random session ID (เช่น09497d46978bf6f32265fefb5cc52264) - เก็บ
{current_user_id: 1}(Base64-encoded) ใน attributedata - ส่ง session ID กลับ browser ผ่าน
Set-Cookie
Request ถัดไป:
- Browser ส่ง cookie เดียวกันผ่าน
Cookie:header (เช่นCookie: _my_app_session=09497d46978bf6f32265fefb5cc52264; path=/; HttpOnly) - ตอน
session[:current_user_id]: - App ดึง session ID จาก cookie หา record ใน
sessionstable - คืน
current_user_idจากdataattribute
ไม่ว่าเก็บใน database, Memcached, Redis หรือที่ไหน กระบวนการคล้ายกัน Cookie แค่ มี session ID Rails app lookup data ใน session store ด้วย ID นั้น
Cookie Store, Cache Store, หรือ Database Store?
ตอนทำงาน เก็บ sessions ใน cookies ไปไกลสุดง่าย ไม่ต้อง infrastructure หรือ setup เพิ่ม
แตตอนต้องขยับ cookie session store มี 2 ทาง:
เก็บใน database หรือเก็บใน cache
เก็บ Sessions ใน Cache
อาจ用 Memcache cache partials หรือ data อยู่ ถ้าใช่ cache store เป็นที่เก็บ session data ที่สองสุดง่าย เพราะ setup แล้ว
ไม่กังวล session store ใหญ่เกิน sessions เก่า auto kicked out ถ้า cache ใหญ่เกิน และเร็ว เพราะ cache อยู่ใน memory
แตไม่สมบูรณ์:
- ถ้าจริงๆ อยากเก็บ old sessions ไม่อยากให้ kicked out
- Sessions และ cached data ต่อยกันพื้นที่ memory ไพ่ cache misses และ sessions หมดอายุเร็ว
- reset cache (เช่น upgrade Rails cached data เก่าไม่ accurate) ไม่มีทาง reset โดยไม่ expire ทุกคน sessions
อยู่ดี Avvo 用วิธีนี้ ใช้งานได้ดี
เก็บ Sessions ใน Database
อยากเก็บ session data จนกว่าจะหมดอายุจริง เก็บใน database Redis, ActiveRecord, หรืออื่นๆ
แต database session storage มี drawbacks:
บาง database stores sessions ไม่ cleanup อัตโนมัติ
ต้อง cleanup expired sessions เอง
ต้องรู้ database behave ยังไงตอนเต็ม session data
用 Redis session store? พยายามเก็บทุก session data ใน memory? Server มี memory พอ หรือ swap จน ssh เข้าแก้ไม่ได้?
ระวังตอนสร้าง session data ไม่งั้น database เต็ม useless sessions
เช่น touch session ทุก request googlebot สร้าง hundreds of thousands useless sessions ผิดหวัง
ปัญหาส่วนใหญ่ rare แตควรรู้
ควรเก็บ Sessions อย่างไร?
มั่นใจว่าไม่เจอ cookie store limitations 用มัน ไม่ต้อง setup มาก และไม่ headache maintain
Cache vs database คือ judgment call เกี่ยวกับ expire session เร็วเกินไปแย่แค่ไหน ผม treat session data ว่า temporary ค่อนข้าง cache store ใช้งานดี ลอง cookie ก่อน แล้ว cache แล้ว database
คุณล่ะ? เก็บ คุณ sessions ยังไง? Comment บอกมา!
อยากเรียนรู้ Ruby/Rails internals เพิ่ม อ่าน: How do gems work? หรือสนใจ web works อ่าน: A web server vs. an app server