Chủ Nhật, 23 tháng 10, 2016

Continuous Integration

Continuous Integration Là Gì

Tích hợp liên tục (CI) là phương pháp phát triển phần mềm đòi hỏi các thành viên trong nhóm tích hợp công việc thường xuyên. Mỗi ngày, các thành viên đều phải theo dõi và phát triển công việc của họ ít nhất một lần. Việc này sẽ được một nhóm khác kiểm tra tự động, nhóm này sẽ tiến hành kiểm thử truy hồi để phát hiện lỗi nhanh nhất có thể. Cả nhóm thấy rằng phương pháp tiếp cận này giúp giảm bớt vấn đề về tích hợp hơn và cho phép phát triển phần mềm gắn kết nhanh hơn.

Continuous IntegrationVòng đời phát triển phần mềm theo phương pháp CI

Tại sao nên dùng CI ?

Sử dụng phương pháp CI giúp cho hệ thống luôn đảm bảo là build được và chạy đúng (do phải pass qua toàn bộ test case). Mặt khác các công đoạn test sẽ được hệ thống CI server thực hiện tự dộng giúp cho ta có thể dễ dàng biết được tình trạng của một branch, một commit nào đó và không cần lấy source về test thử. Do đó tốc độ phát triển được tăng lên. Đây cũng là lý do mà nhiều team phát triển theo mô hình Agile lựa chọn phương pháp này.
Hiện tại các công ty lớn thường triển khai các hệ thống CI cho riêng mình hoặc sử dụng dịch vụ của hãng thứ 3. Một số framework được sử dụng phổ biến như:
  • Team Foundation Server - Microsoft
  • TeamCity - Jet Brains
  • Hudson
  • Jenkin
  • Travis CI
  • GitLab CI
Ngoài ra còn nhiều dịch vụ khác.

Workflow của CI

Workflow của phương pháp CI được chia thành 6 bước như sau:
Bước 1 Các người phát triển sẽ đưa phần source mà họ đã thay đổi lên Source Control Server. Khi đó Source Control Server sẽ thông báo với CI Server là có bản source mới.
Bước 2 CI Server lấy source mới về
Bước 3, 4 & 5 CI Server sẽ build, test và cập nhật lại trạng thái build của bản source đó.
Bước 6 CI Server sẽ thông báo đến người quản lý và các người phát triển về tình trạng của bản code mới.
Continuous Integration Workflow

Một hệ thống CI thông thường thực hiện những tác vụ sau:
  1. Phát hiện thay đổi trong source code repository (xuất hiện commit mới)
  2. Phân tích chất lượng source code
  3. Thực hiện build
  4. Chạy toàn bộ unit test
  5. Chạy toàn bộ integration test
  6. Sinh ra những tạo tác có thể triển khai được, gọi là deployable artifact
  7. Có thể, deploy những artifact này và thực hiện những kiểm thử khác nếu cần
Nếu một trong những bước trên không thành công:
  • Tuỳ thuộc vào mức độ nghiêm trọng, việc tích hợp có thể dừng lại hoặc đi tiếp
  • Kết quả tích hợp được thông báo tới nhóm phát triển qua email, hệ thống chat. Thông qua sour code repository, CI có thể nhận biết cá nhân đã thực hiện việc commit gây ra lỗi trong việc tích hợp.
  • Nhóm phát triển hoặc cá nhân thực hiện commit thực hiện sửa lỗi và commit
  • CI phát hiện thay đổi trong source code repository và thực hiện lại những bước trên
Trong những tác vụ trên, tác vụ 1, 3, 6 thực sự rất dễ thực hiện và được hỗ trợ bởi hầu hết những công cụ CI hiện có trên thị trường. Những tác vụ 2, 4, 5 không đơn giản chỉ là sự hỗ trợ của công cụ, tư tưởng và cách thực hiện phía sau quan trọng hơn rất nhiều; chúng ta sẽ bàn về những vấn đề này ở những bài viết sau. Tác vụ 7 lại liên quan tới một hệ thống CD (Continuos Deployment – triển khai liên tục) với tư tưởng giống với CI nhưng dưới góc độ “triển khai” và lại phụ thuộc vào tần suất release của sản phẩm và độ phức tạp của môi trường nên không hẳn là một công cụ tiên quyết trong việc thực hành Agile.
Tuy vậy, nhiều nhóm thực hành Agile vẫn lựa chọn việc triển khai CI và CD đồng thời bởi một trong những best practice của CI là đảm bảo môi trường đồng nhất (hoặc gần giống nhất) giữa môi trường kiểm thử (tích hợp) và môi trường production.
Chúng ta dễ dàng nhận thấy ưu điểm của commit build so với daily build vì cô lập được thay đổi theo từng commit khiến việc xử lý xung đột đơn giản hơn. Tuy vậy, thời gian để CI thực hiện toàn bộ 7 tác vụ trên có thể rất nhiều với một số môi trường của dự án khiến việc này không khả thi; nên nhiều nhóm thực hành Agile vẫn lựa chọn daily build. Tôi là một người theo trường phái commit build và luôn cố gắng duy trì CI theo cách này. Với những dự án phức tạp, tôi thường sử dụng nhiều build agent để thực hiện việc tích hợp song song với những commit cùng thời điểm. Một giải pháp khác là, lược bỏ những tác vụ không cần thiết (ví dụ tác vụ 7) để vẫn thực hiện việc tích hợp với từng commit và thực hiện một “long build” vào cuối ngày.
Hiện nay có rất nhiều công cụ CI cho phép nhóm thực hành Agile lựa chọn với những tác vụ cơ bản như trên, phổ biến nhất có lẽ là Jenkins – hệ thống mã nguồn mở với rất nhiều plugin phù hợp với nhiều điều kiện hệ thống khác nhau. Tôi cũng là một kẻ hâm mộ Jenkins nhưng lại thường sử dụng những công cụ khác khi có thể, chỉ bởi giao diện của Jenkins thì quá tệ và cũng vì cónhiều người sử dụng quá.

Servlet

Servlets là gì?

Java Servlets là các chương trình chạy trên một Web server hoặc một Application server và thực hiện như là một tầng trung gian giữa một Yêu cầu từ một trình duyệt web hoặc HTTP client với các Database hoặc các ứng dụng trên HTTP server.
Sử dụng Servlets, bạn có thể thu thập Input từ người sử dụng thông qua các form trên trang web, hiển thị các bản ghi (record) từ một Database hoặc từ nguồn khác, và tạo các trang web động.
Java Servlets thường có chung mục đích: là các chương trình độc lập bởi việc sử dụng Common Gateway Interface (CGI). Nhưng so với CGI, thì Servlets có các lợi thế sau:
  • Hiệu năng tốt hơn đáng kể.
  • Servlets thực thi bên trong không gian địa chỉ của một Web server, không cần thiết phải tạo một tiến trình riêng biệt để xử lý mỗi yêu cầu từ Client.
  • Servlets là độc lập trên nền tảng bởi vì chúng được viết bằng Java.
  • Bởi vì viết bằng Java (mà Java cung cấp tình bảo mật cao trên Server) nên Servlets là đáng tin cậy.
  • Tính năng đầy đủ của thư viện của các lớp trong Java là luôn luôn có sẵn cho Servlets. Nó có thể giao tiếp với Applet, Database hoặc phần mềm khác thông qua các Socket và kỹ thuật RMI mà bạn đã từng thấy.

Cấu trúc của Servlets

    • javax.servlet package chứa 1 abstract class tên là GenericServlet
      • Các GenericServlet kế thừa từ lớp Object và giúp thiết kế một giao thức servlet độc lập
      • Các GenericServlet triển khai ba interface:
        • Servlet: định nghĩa vòng đời của Servlet.
        • ServletConfig: định nghĩa các method được sử dụng bởi Servlet container để truyền thông tin tới 1 Servlet mà nó khởi tạo.
        • Serializable: được định nghĩa trong java.io package để sắp đặt trạng thái của 1 đối tượng.
    • Lớp HTTPServlet là một lớp con của GenericServlet và cho phép để tạo ra một Servlet dựa trên HTTP như là một phần của một ứng dụng Web.


    Package trong Servlets

    Java Servlets là các lớp trong Java chạy bởi một Web Server mà có một trình thông dịch hỗ trợ Java Servlets.
    Servlets có thể được tạo bởi sử dụng các gói javax.servlet và javax.servlet.http là một phiên bản mở rộng của thư viện lớp Java để hỗ trợ các dự án phát triển có phạm vi lớn. Các lớp này triển khai Java Servlet và JSP.
    Java Servlet đã được tạo và được biên dịch giống như các lớp khác trong Java. Sau khi bạn cài đặt các gói servlet và thêm chúng vào Classpath trong máy của bạn, bạn có thể biên dịch Servlet với bộ biên dịch JDK hoặc bất kỳ bộ biên dịch nào khác.
    ServletConfig
    • Chỉ một ServletConfig chi một servlet
    • ServletContext: Chỉ một ServletContext cho một web app (trong một JVM). ServletContext được dùng để lấy các thông tin về môi trường thực thi của container.
    • Có 2 cách để lấy ServletContext:
      • getServletContext(); (method của Servlet interface)
      • getServletConfig.getServletContext();
    • Hai cách trên đều dùng được trong Servlet. Cách thứ 2 có ích khi ta muốn get ServletContext từ các object không phải là Servlet như các POJO class bằng cách truyền ServletConfig qua lại giữa các class.
    • Chú ý: Chúng ta chỉ có thể get một object từ một object khác mà có life time nhỏ hơn. 
    Vòng đời (Life Cycle) của Servlet

      • Vòng đời của Servlet có thể được định nghĩa như là một tiến trình đầy đủ từ khi được tạo ra đến khi bị hủy. Một Servlet theo các giai đoạn sau:
        • Servlet được khởi tạo bởi gọi phương thức init().
        • Servlet gọi phương thức service() để xử lý một yêu cầu từ Client.
        • Servlet bị hủy bởi triệu hồi phương thức destroy().
        • Cuối cùng, servlet trở thành rác và được thu thập bởi Garbage Collector của JVM.

    Phương thức init()

    • Phương thức được thiết kế để chỉ được gọi một lần. Nó được gọi khi Servlet lần đầu được tạo, và không được gọi lại cho mỗi yêu cầu của người dùng. Vì thế, nó được sử dụng cho các khởi tạo one-time, giống như phương thức init của Applet.
      Thường thì, Servlet được tạo khi một người dùng lần đầu triệu hồi một URL tương ứng với Servlet đó, nhưng bạn cũng có thể xác định rằng Servlet này được tải khi Server được khởi động lần đầu.
      Khi một người sử dụng triệu hồi một Servlet, một đối tượng đơn của Servlet được tạo, với mỗi yêu cầu từ người dùng, là kết quả trong một thread mới, mà được thao tác tới doGet hoặc doPost một cách thích hợp. Phương thức init() tạo hoặc tải một vài dữ liệu mà sẽ được sử dụng qua vòng đời của Servlet đó.
      Định nghĩa phương thức init() như sau:
      public void init() throws ServletException {
        // Initialization code...
      }

    Phương thức service()

    • Phương thức service() là phương thức chính để thực hiện tác vụ thực sự. Nơi chứa servlet (ví dụ như Web Server) gọi phương thức service() để xử lý các yêu cầu từ Client (hoặc trình duyệt) và viết phản hồi đã được định dạng trở lại Client đó.
      Mỗi khi Server nhận một yêu cầu cho một Servlet, thì Server tạo một Thread mới và triệu hồi service(). Phương thức service() kiểm tra kiểu yêu cầu HTTP (Kiểu GET, POST, PUT, DELET, .v.v.) và gọi các phương thức doGet, doPost, doPut, doDelete .v.v. tương ứng một cách thích hợp.
      Đây là minh họa cho phương thức service():
      public void service(ServletRequest request, 
                          ServletResponse response) 
            throws ServletException, IOException{
      }
      Phương thức service() được gọi bởi Container và nó triệu hồi các phương thức doGet, doPost, doPut, doDelet, .v.v. tương ứng. Vì thế, bạn không phải làm gì cả với service() nhưng việc bạn ghi đè phương thức hoặc doGet() hoặc doPost tùy thuộc vào kiểu yêu cầu mà bạn nhận từ Client.
      Hai phương thức doGet() và doPost() được sử dụng thường xuyên nhất với mỗi service. Sau đây là chi tiết về hai phương thức này:

    Phương thức doGet()

    • Một yêu cầu GET, là kết quả từ một yêu cầu chuẩn cho URL hoặc từ một HTML form, mà không có PHƯƠNG THỨC nào được xác định và nó nên được xử lý bởi phương thức doGet().
      public void doGet(HttpServletRequest request,
                        HttpServletResponse response)
          throws ServletException, IOException {
          // Servlet code
      }

    Phương thức doPost()

    • Một yêu cầu POST, là kết quả từ một HTML form mà liệt kê POST như là PHƯƠNG THỨC, và nên được xử lý bởi phương thức doPost():
      public void doPost(HttpServletRequest request,
                         HttpServletResponse response)
          throws ServletException, IOException {
          // Servlet code
      }

    Phương thức destroy()

    • Phương thức destroy() chỉ được gọi một lần ở giai đoạn cuối trong vòng đời Servlet. Phương thức này giúp servlet của bạn một cơ hội để đóng các kết nối tới Database, dừng thread, viết các danh sách cookie hoặc viết tính toán trên đĩa, và thực hiện các hoạt động cleanup khác.
      Sau khi phương thức destroy() được gọi, đối tượng servlet này được đánh dấu cho Garbage Collector. Phương thức này trông giống như sau:
        public void destroy() {
          // Finalization code...
        }

    Sơ đồ cấu trúc vòng đời của Servlet

    • Sơ đồ sau miêu tả các giai đoạn trong vòng đời của một Servlet đặc trưng:
      • Đầu tiên, các HTTP Request tới Server và được đưa tới Container của Servlet.
      • Container Servlet tải các servlet trước khi gọi phương thức service().
      • Sau đó Container Servlet xử lý nhiều yêu cầu bởi việc tạo nhiều thread, mỗi thread thực thi phương thức service() cho một đối tượng servlet đơn.
      Vòng đời của Servlet

    Nhiệm vụ của Servlets

    Servlets thực hiện các tác vụ chủ yếu sau:
    • Đọc dữ liệu hiển thị (explicit) được gửi bởi Client (hoặc trình duyệt) bao gồm một HTML Form trên một trang web hoặc nó cũng có thể từ một Applet hoặc một chương trình Custom từ HTTP Client.
    • Đọc dữ liệu yêu cầu HTTP ẩn (implicit) được gửi bởi Client (hoặc trình duyệt) bao gồm cookie, các loại media.
    • Xử lý dữ liệu và cho ra kết quả. Tiến trình này có thể yêu cầu Database, đang thực thi một triệu hồi tới RMI hoặc CORBA, triệu hồi một Web Service, hoặc tính toán phản hồi một cách trực tiếp.
    • Gửi dữ liệu hiển thị (ví dụ: tài liệu) tới các Client (hoặc trình duyệt). Tài liệu này có thể được gửi theo nhiều định dạng khác nhau, gồm text (HTML hoặc XML), nhị phân (hình ảnh GIF), Excel, .v.v.
    • Gửi phản hồi HTTP ẩn tới các Client (hoặc trình duyệt), thông báo cho trình duyệt hoặc Client về kiểu của tài liệu được trả về (ví dụ: HTML), thiết lập các Cookie và Caching các tham số, cùng các tác vụ khác.

    Phân tích.


    • 1 servlet hoạt động nhờ 1 container gọi là Servlet Container. method service() được coi như là hiện thân của Container để kiểm soát hoạt động xử lí các request từ client.
    • Trong 1 servlet chỉ có 1 ServletConfig.

    => Kết luật :
    Servlet được sử dụng để thay thế cho những công nghệ Web động. Việc sử dụng Servlet mang lại những lợi thế:
    • Dễ di chuyển. Servlet được viết bằng Java nên nó có tính di động cao, thực hiện được trên nhiều hệ điều hành, trên các Web Server khác nhau. Khái niệm “Viết một lần, chạy ở mọi nơi” cũng rất đúng với Servlet.
    • Mạnh mẽ. Servlet hỗ trợ rất hiệu quả cho việc sử dụng các giao diện lõi API như lập trình mạng, xử lý đa luồng, xử lý ảnh, nén dữ liệu, kết nối các CSDL, bảo mật, xử lý phân tán và triệu gọi từ xa RMI, CORBA, v.v. Nó cũng thích hợp để trao đổi tin, truyền thông giữa Client và Server một cách bình thường.
    • Hiệu quả. Servlet có tính hiệu quả cao. Một khi được tải về, nó sẽ được lưu lại trong bộ nhớ của máy chủ. Servlet duy trì các trạng thái của nó, do vậy những tài nguyên ngoại như việc kết nối với CSDL cũng sẽ được lưu giữ lại.
    • An toàn. Bởi vì Servlet được viết bằng Java nên nó kế thừa được tính an toàn của Java. Cơ chế tự động dọn rác và việc không sử dụng con trỏ của Java giúp cho Servlet thoát khỏi nhiều công việc quản lý bộ nhớ. Đồng thời nó xử lý các lỗi rất an toàn theo cơ chế xử lý ngoại lệ của Java.
    • Tính tích hợp. Các Servlet được tích hợp với các Server. Chúng cộng tác với các Server tốt hơn các chương trình CGI.
    • Tính linh hoạt. Các Servlet hoàn toàn mềm dẻo. Một HTTP Servlet được sử dụng để tạo ra một trang Web, sau đó ta có thể sử dụng thẻ <Servlet> để đưa nó vào trang Web tĩnh, hoặc sử dụng với các Servlet khác để lọc ra các nội dung cần thiết.
    Servlet có một số ưu điểm so với CGI:
    • Một Servlet không làm việc trong một tiến trình riêng. Điều này loại bỏ được việc phải tạo ra quá nhiều tiến trình mới cho mỗi yêu cầu.
    • Một Servlet sẽ thường trực trong bộ nhớ giữa các yêu cầu, trong khi các chương trình CGI cần phải tải xuống và được khởi động cho từng yêu cầu CGI.
    • Chỉ cần một Servlet trả lời đồng thời cho tất cả các yêu cầu. Điều này cho phép tiết kiệm được bộ nhớ và đảm bảo nó dễ dàng quản lý được dữ liệu một cách thống nhất.
    • Một Servlet có thể thực hiện bởi một Servlet Engine trong phạm vi kiểm soát Sandbox để đảm bảo an toàn trong việc sử dụng các Servlet.


    Thứ Tư, 19 tháng 10, 2016

    Security(SQL Injection, Statement, PrepareStatement, CallableStatement)

    Security
    1.SQL Injection
    SQL Injection là một trong những kiểu hack web đang dần trở nên phổ biến hiện nay. Bằng cách inject các mã SQL query/command vào input trước khi chuyển cho ứng dụng web xử lí, bạn có thể login mà không cần username và password
    1. SQL Injection là gì?
    SQL injection là một kỹ thuật cho phép những kẻ tấn công lợi dụng lỗ hổng của việc kiểm tra dữ liệu đầu vào trong các ứng dụng web và các thông báo lỗi của hệ quản trị cơ sở dữ liệu trả về để inject (tiêm vào) và thi hành các câu lệnh SQL bất hợp pháp. SQL injection có thể cho phép những kẻ tấn công thực hiện các thao tác, delete, insert, update, v.v. trên cơ sở dữ liệu của ứng dụng, thậm chí là server mà ứng dụng đó đang chạy. SQL injection thường được biết đến như là một vật trung gian tấn công trên các ứng dụng web có dữ liệu được quản lý bằng các hệ quản trị cơ sở dữ liệu như SQL Server, MySQL, Oracle, DB2, Sysbase...

    Các kiểu tấn công phổ thông

    -Tấn công bằng mệnh đề luôn đúng

    Những lỗi lập trình này thường xảy ra ở các chức năng tìm kiếm hoặc đăng nhập tài khoản. Ví dụ một câu lệnh SQL như sau:
    SELECT * FROM accounts WHERE userName = '{$userName}'
    Câu lệnh này đầy sơ hở, chắc là ít người có thể liều lĩnh mà code như vậy, tuy nhiên thực tế thì nó cũng gần như thế mà thôi, rất nhiều trang mắc lỗi này, giờ chúng ta thử xem hacker sẽ thêm cái gì:
    ' or '1' = '1'
    Thì khi truy vấn, câu lệnh của chúng ta sẽ trở thành mệnh đề luôn đúng như dưới đây
    SELECT * FROM accounts WHERE userName = '{$userName}' OR '1' = '1'
    Câu lệnh này có vế luôn trả về đúng, cho nên câu lệnh luôn thực hiện được, trong trường hợp này thì tài khoản bị mất là cái chắc chắn, hoặc hacker sẽ đăng nhập như admin mà nghịch ngợm phá hoại …

    -Tấn công phá hoại dữ liệu

    Giả sử câu lệnh cũng như trên, nhưng không nhập ‘1’ = ‘1’ nữa mà thêm như sau:
    SELECT * FROM accounts WHERE userName = '{$userName}'; DROP TABLE accounts; ''
    Dấu ( ; ) dùng để phân tách câu lệnh trong SQL, điều này đồng nghĩa với việc hacker có thể hành động thêm bất kì lệnh gì vào trong câu lệnh trên, rất nguy hiểm, nếu các bạn không có bản backup thì nguy to.

    Phòng chống SQl Injection

    Hầu hết các mã nguồn mở bây giờ đều không quá lo về lỗi này, tuy nhiên plugin hay module được viết bởi nhiều lập trình viên khác nhau lại hay để ra sơ hở tạo điều kiện cho lỗi phát sinh.
    Cách phòng tránh thì có nhiều cách, trong đó:

    1. Viết lại đường dẫn

    Viết lại đường dẫn của website có thể phòng được lỗi SQL Injection, vì hacker thường phải tìm một sơ hở của website trên đường link hoặc trên form nhập liệu của người dùng, khi không nhìn thấy biến query thì hacker phải tìm cách khác để thử lỗi.

    2. Lọc kĩ những gì người dùng nhập

    Bài học là đừng bao giờ tin người dùng, kể cả bản thân sẽ giúp bạn phòng lỗi này cực kì hiệu quả, giả dụ như sau:
    Với số người dùng nhập vào, để ăn chắc các bạn lọc qua các hàm như:
    $num = ( int ) $_POST['num'];
    $num = is_numeric ( $num ) ? $num : 0;
    Ví dụ sử dụng sprinf:
    $data = sprintf('select * from %s where data = %d limit 1', $table, $must_be_number );
    Sử dụng kết hợp với mysql_real_escape_string() để câu SQL được an toàn:
    $data = sprintf('select * from %s where data = %d limit 1', $table, mysql_real_escape_string($must_be_number ) );
    Với các cách trên, bạn có thể yên tâm là câu lệnh của mình khó bị bóp méo qua lỗi SQL Injection !

    Tổng kết

    Lỗi SQL Injection là lỗi rất phổ thông, tuy nhiên phòng chống nó là việc hoàn toàn không khó, chỉ cần bạn luôn tự nhủ là với những gì người dùng nhập ta không thể tin bất kì điều gì, phải xác định lại chúng hoặc sử dụng phương pháp ép kiểu hoặc thêm dấu “” vào trong biến người dùng nhập ( addslashes() ) sẽ hạn chế tối đa lỗi này !
    Với các mã nguồn mở, chúng ta có thể an tâm phần nào vì hầu hết các câu query đều được lọc qua lọc lại một cách kĩ lưỡng, chỉ phát sinh lỗi này khi chúng ta viết không đúng quy chuẩn mà thôi, các bạn cũng nên để ý sử dụng plugin và module của người dùng xác định được download trên trang chủ nhé !

    2. Statements

    -Khi làm việc với JDBC, bạn không thể không biết đến các interface hỗ trợ cho quá trình khai thác và lưu trữ thông tin trên cơ sở dữ liệu của chương trình chính là Statement,PreparedStatement và CallableStatement. Tùy theo nhu cầu, bạn có thể tạo ra các đối tượng của một trong các interface trên để thực hiện nhu cầu khai thác thông tin của chương trình tại thời điểm cần thiết.

    -Việc sử dụng các câu lệnh SQL để truyền giữa client và database server sẽ làm cho lưu lượng truyền thông trên mạng rất lớn. Điều này làm tăng traffic trên mạng dẫn đến tốc độ thực thi của chương trình giảm, tốn kém tài nguyên tại database server vì cứ luôn phải cấp phát cho việc tạo và giải phóng bộ nhớ khi thực thi các lệnh SQL, cho dù là lệnh đó được thực thi nhiều lần.

    -Stored procedure là giải pháp tốt cho tình huống này, việc sử dụng stored procedure để hỗ trợ cho quá trình xử lý thông tin trong database tỏ ra khá hiệu quả bởi 1 số ưu điểm sau:

         +Có thể gọi thực thi nhiều công việc tác động lên Database chỉ thông qua 1 cái tên.
       +Giảm traffic do chỉ truyền 1 chuỗi ký tự ngắn chính là tên của stored procedure mà không phải truyền đi về những câu lệnh SQL dài dòng, đôi khi lên tới cả trăm ký tự.
        +Stored procedure được tạo và đặt tại database server và việc khai thác chỉ thông qua tên của nó cho nên có thể ngăn ngừa được những kẻ tò mò muốn biết chương trình của chúng ta đang tác động như thế nào lên Database.
        +Stored procedure được biên dịch trước và tồn tại mãi trong quá trình DBMS hoạt động nên khả năng thực thi và hồi đáp thông tin cho client rất nhanh, tăng hiệu suất thực thi của chương trình. Stored procedure được tái sử dụng nhiều lần.
        +Tận dụng việc thực thi và giải quyến các yêu cầu của chương trình ở đồng thời cả 2 nơi :client – server. Vì thế tăng hiệu suất thực thi chương trình.
    -Stored procedure có nhiều ưu điểm như thế, vậy để gọi sử dụng các stored procedure trong Database ta sẽ dùng đối tượng nào ? Chắc các bạn cũng đã đoán ra, đúng thế Java cung cấp cho chúng ta interface CallableStatement để có thể gọi các stored proceduretrong Database.

    II. Hướng dẫn sử dụng Statement, PreparedStatement và CallableStatement
    Trong hướng dẫn này tôi sẽ dùng 1 database có sẵn với 1 bảng tên là Logon có các cột UserName(primary key), Password, FullName, Role có phát sinh đoạn coad như sau:
    CREATE TABLE [dbo].[Logon](
     [UserName] [varchar](50) NOT NULL PRIMARY KEY,
     [Password] [varchar](50) NOT NULL,
     [FullName] [varchar](50) NOT NULL,
     [Role] [varchar](50) NOT NULL,
    )

    Trường hợp 1: Câu truy vấn dữ liệu.
    1.Sử dụng Statement
    Để sử dụng đối tượng của interface Statement:
    _Tạo 1 thể hiện của interface này thông qua phương thức createStatement() của đối tượng Connection.
    _Tạo 1 câu truy vấn đến DB.
    _Gọi phương thức executeQuery() để trả về kết quả là 1 ResultSet.
    Như vậy, ta xây dựng 1 hàm như sau:
    public ResultSet getAccounts() throws Exception{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            Connection con = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;database=Sinhvien", "sa", "");
            String strSQL = "Select * from Logon";
            Statement st = con.createStatement();
            ResultSet rs = st.executeQuery(strSQL);
            return rs;
        }
    2. Sử dụng PreparedStatement
    Để sử dụng đối tượng của interface PreparedStatement:
    _Tạo 1 thể hiện của interface này thông qua phương thức prepareStatement() của đối tượng Connection.
    _Tạo 1 câu truy vấn đến DB
    _Gọi phương thức executeQuery() để trả về kết quả là 1 ResultSet.
        public ResultSet getAccounts(String role) throws Exception{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            Connection con = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;database=Sinhvien", "sa", "");
            String strSQL = "Select * from Logon";
            PreparedStatement ps = con.prepareStatement(strSQL);
            ResultSet rs = ps.executeQuery();
            return rs;
        }
    3. Sử dụng CallableStatement
    Để sử dụng đối tượng của interface CallableStatement:
    _Tạo 1 Store Procedure như sau:
    CREATE PROCEDURE getAccounts
    AS
    BEGIN
     SELECT * FROM Logon
    END
    _Tạo 1 chuỗi mô tả cho việc gọi Stored procedure trong cơ sở dữ liệu theo cú pháp {call  <tên_sp>(?,?,?,…) } (Trong đó tương ứng với mỗi dấu ? là 1 tham số của store procedure đã tạo trong Database )
    _Tạo 1 thể hiện của interface CallableStatement thông qua phương thức prepareCall() dựa trên đối tượng Connection
    _Gọi phương thức executeQuery() để trả về kết quả là 1 ResultSet.
        public ResultSet getAccounts() throws Exception{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            Connection con = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;database=Sinhvien", "sa", "");
            String strCall = "{call getAccounts}";
            CallableStatement caSt = con.prepareCall(strCall);
            ResultSet rs = caSt.executeQuery();
            return rs;
        }

    Trường hợp 2: Thao tác dữ liệu cho DB
    1.Sử dụng Statement
    Tôi sẽ demo thao tác insert dữ liệu vào bảng Logon.
    public void insertAccount(String user, String pass, String fullName,
                String role) throws Exception{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            Connection con = DriverManager.getConnection("jdbc:sqlserver://"
                    + "localhost:1433;database=Sinhvien", "sa", "");
            String strSQL = "insert into Logon values('"+user+"','"+pass+"','"+
                    fullName+"','"+role+"')";
            Statement st = con.createStatement();
            st.execute(strSQL);
        }
    2.Sử dụng PreparedStatement
    Tôi sẽ demo thao tác update dữ liệu có trong bảng Logon.
    public void updateAccount(String user, String pass, String fullName,
                String role) throws Exception{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            Connection con = DriverManager.getConnection("jdbc:sqlserver://"
                    + "localhost:1433;database=Sinhvien", "sa", "");
            String strSQL = "update Logon set Password=?, FullName=?, Role=?"
                    + "where UserName=?";
            PreparedStatement ps = con.prepareStatement(strSQL);
            ps.setString(1, pass);
            ps.setString(2, fullName);
            ps.setString(3, role);
            ps.setString(4, user);
            ps.execute();
        }
    3.Sử dụng CallablStatement
    Tôi sẽ demo thao tác delete record có trong bảng Logon
    _Tôi có Store Procedure như sau:
    CREATE PROCEDURE deleteAccount
    @username VARCHAR(50)
    AS
    BEGIN
     DELETE FROM Logon WHERE [UserName]=@username
    END
    _Tôi gọi Store Procedure như sau:
    public void deleteAccounts(String user) throws Exception{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            Connection con = DriverManager.getConnection("jdbc:sqlserver://"
                    + "localhost:1433;database=Sinhvien", "sa", "");
            String strSQL = "{call deleteAccount(?)}";
            CallableStatement cs = con.prepareCall(strSQL);
            cs.setString(1, user);
            cs.execute();
        }

    Thứ Năm, 13 tháng 10, 2016

    Restful Webservice

    RESTful Web services

    RESTful Web Services là một thuật ngữ được sử dụng rất nhiều trong những năm gần đây. Tuy nhiên không ít người cảm thấy khó hiểu về khái niệm này khi mà thậm chí có bạn nói đã Google hàng giờ mà vẫn ...không hiểu gì hết. Chính vì thế RESTful Web Services luôn trở thành nỗi ám ảnh cho các bạn lập trình viên trẻ khi phải đối mặt với các nhà tuyển dụng đặc biệt là khi nó được theo sau bởi một cùm từ cũng khó hiểu chẳng kém là Web Services phía sau nó.
    Tin đặc biệt tốt là thực ra RESTful Web Services không khó hiểu và đáng sợ như khi bạn bị mấy tay tuyển dụng đặt câu hỏi trong buổi phỏng vấn để 'dìm hàng', 'dìm luôn lương' bạn. Ngay bây giờ mình sẽ giải thích một cách ngắn gọn đi vào thực tiễn bằng ví dụ luôn chứ không lý thuyết lơ tơ mơ như mấy trang khác để giúp các bạn hiểu RESTful là cái quái gì mà mấy anh trên mạng giải thích lằng nhằng khó hiểu thế.
    Thế nên mình xin phép bắt đầu bằng 1 ví dụ và ném cái định nghĩa dài loằng ngoằng ở cuối bài nhoé :-)
    Giả sử bạn cần tạo một trang blog cá nhân về học lập trình. Trên trang này có những bài viết (tiếng Anh nó gọi là articleđấy). Các bài viết sẽ được tạo ra bởi một tác giả nào đó, sau đó tác giả này có thể chỉnh sửa bài viết, tiếp đó sau khi chỉnh sửa chán chê thì tác giả có thể quyết định cập nhật bài viết. Và cuối cùng nếu tác giả thấy bài mình viết ra chuối quá éo có ai thèm đọc cả thì tác giả có thể chọn cách xoá bài viết cho khỏi phải nhìn thấy đỡ cảm thấy nhục : ))
    4 hành động trên: tạo ra bài viết (create), chỉnh sửa bài viết (edit), cập nhật bài viết (update) hay xoá bài viết (delete) tương ứng với 4 cách thức mà một tài nguyên được quản lý (ở đây tài nguyên chính là bài viết, tuy nhiên tài nguyênhay resource không chỉ giới hạn ở bài viết mà nó còn có thể là tài khoản người dùng, cũng được quản lý thông qua 4 hành động tạo ra tài khoản hay đăng ký, chỉnh sửa thông tin tài khoản, cập nhật thông tin tài khoản và xoá tài khoản).
    Cảm thấy 4 hành động trên sẽ là một công việc quá phổ biến đối với hầu hết các trang web (bạn cứ tưởng tượng xem ngay cả 1 trang thuộc loại hàng khủng như Facebook thì người dùng cũng chủ yếu là tạo bài viết, chỉnh sửa bài viết, cập nhật bài viết và xoá bài viết, tương tự cho thông tin tài khoản), nên đã có một vị Giáo sư đại tài (mà mình quên mịa mất tên bác ấy rồi) chế hẳn ra một quy luật thống nhất như sau để cho tất cả các lập trình viên cứ thế mà làm theo mỗi lần phải lập trình một trang có 4 chức năng trên. Bác này phát biểu quy luật như sau:
    • Khi tạo ra một resource thì các chú cố gắng sử dụng phương thức POST để gửi dữ liệu lên máy chủ nhé (cái này nếu học HTML thì bạn sẽ nhớ ra là phải để thuộc tính method="POST" khi tạo một biểu mẫu. Ví dụ như sau:<form method="POST" action="url-la-cai-me-gi-cung-duoc-het-á.php"></form>.
    • Khi tạo cập nhật một resource thì các chú cứ cố gắng sử dụng phương thức PUT nhé (chú nào mà không làm thì coi chừng thằng đồng nghiệp nó chửi cả thầy lẫn trò khi phải viết lại code của chú đấy!)
    • Khi xoá một resource thì các chú cứ cố gắng sử dụng phương thức DELETE nhé.
    • Và cuối cùng là khi hiển thị một bài viết cho độc giả họ đọc thì sử dụng phương thức GET.
    Tóm lại, RESTful service nghe màu mè nhưng rốt cuộc chỉ có thế thôi. Nó là một kiến trúc thống nhất giúp thiết kế các website để có thể dễ dàng quản lý các tài nguyên. Nó không phải là một quy luật buộc bạn phải tuân theo mà đơn giản là một kiến trúc được đề xuất ra và kiến trúc này hiện đang được sử dụng rất phổ biến vì tính đơn giản, dễ hiểu và rất ưu việt của nó. Nhân tiên nhớ ra là REST được đề xuất bởi nhà khoa học máy tính Roy Thomas Fielding vào năm 2012.
    Ơ chứ không phải chú mày mới viết ở trên RESTful là 1 quy luật thống nhất à???
    Hic, khúc này thành thật xin lỗi các bạn vì đã ...cố tình viết sai sự thật một tí. RESTful nói đúng hơn là một kiến trúc chứ không phải quy luật. Nhưng mà... nếu mình không viết vậy lại thay bằng chữ kiến trúc chắc hẳn se khiến các bạn khó hiểu vì cái cụm từ hàn lâm này nghe rất trừu tượng (thế nên thôi để chữ quy luât cho các bạn dễ hình dung). Lạc đề tí nhưng mà mình có quen 3 cô tên Trúc cô nào cũng xinh đẹp hết á : )).
    Nói tóm lại RESTful là cái mẹ gì? Vâng thì ngay bây giờ mình xin được đưa ra định nghĩa về REST như đã hứa ở phần đầu bài viết.

    RESTful Là Gì

    REST (Representational State Transfer) đã được chọn sử dụng rộng rãi thay cho Web service dựa trên SOAP và WSDL. Bằng chứng quan trọng của sự thay đổi này chính là việc các công ty dẫn đầu trong lĩnh vực cung cấp dịch vụ mạng 2.0 như Yahoo, Google và Facebook đã phản đối các giao thức dựa trên SOAP hoặc WSDL và ủng hộ phương thức hướng đến tài nguyên và dễ sử dụng đối với các dịch vụ của họ. Trong bài viết này, Alex Rodriguez sẽ giới thiệu với các bạn các nguyên lý cơ bản của REST.

    REST định nghĩa các quy tắc kiến trúc để bạn thiết kế Web services chú trọng vào tài nguyên hệ thống, bao gồm các trạng thái tài nguyên được định dạng như thế nào và được chuyển tải qua HTTP thông qua số lượng lớn người dùng và được viết bởi những ngôn ngữ khác nhau. Nếu tính theo số dịch vụ mạng sử dụng, REST đã nổi lên trong vài năm qua như là một mô hình thiết kế dịch vụ chiếm ưu thế. Trong thực tế, REST đã có những ảnh hưởng lớn và gần như thay thế SOAP và WSDL vì nó đơn giản và dễ sử dụng hơn rất nhiều.

    REST không thu hút được nhiều sự chú ý khi lần đầu tiên giới thiệu vào năm 2000 bởi Roy Fielding trong luận án của ông "Architectural Styles and the Design of Network-based Software Architectures" (Phong cách kiến trúc và thiết kế kiến trúc phần mềm dựa trên mạng) tại Đại học California. Luận án đã phân tích một loạt các nguyên tắc kiến trúc phần mềm sử dụng Web như là một nền tảng tính toán phân tán.Đến nay, vài năm sau đó, đã xuất hiện các framework chủ đạo cho REST và chúng vẫn đang được tiếp tục phát triển, nó đang được xem xét để đưa vào trong bộ Java™ 6 thông qua tiêu chuẩn JSR-311.

    Bài viết này chỉ ra rằng khi REST được biết đến nhiều hơn thì việc cụ thể hóa một Web service REST sẽ tuân thủ theo bốn nguyên tắc thiết kế cơ bản sau:


    Sử dụng các phương thức HTTP một cách rõ ràng
    Phi trạng thái
    Hiển thị cấu trúc thư mục như URls
    Chuyển đổi JavaScript Object Notation (JSON) và XML hoặc cả hai.

    Các phần sau đây sẽ mở rộng dựa trên bốn nguyên lý này và đề xuất một nhân tố kỹ thuật cơ bản giải thích vì sao chúng quan trọng đối với các nhà thiết kế dịch vụ mạng REST.

    Sử dụng các phương thức HTTP một cách rõ ràng

    Một đặc tính quan trọng của dịch Web service RESTful là sử dụng một cách rõ ràng các phương thức HTTP theo cách một giao thức được xác định bởi RFC 2616. Ví dụ HTTP GET được xác định như là một phương thức sinh ra số liệu được sử dụng có chủ đích bởi các ứng dụng người dùng để thu thập tài nguyên, dữ liệu từ một máy chủ, hoặc thực thi một truy vấn mà máy chủ sẽ tìm kiếm và phản hồi cùng với một gói thông tin tương thích.
    REST yêu cầu các nhà phát triển sử dụng phương thức HTTP một cách rõ ràng theo cách tương thích với giao thức chuẩn. Nguyên lý thiết kế REST cơ bản này thiết lập một ánh xạ 1-1 giữa các hành động tạo, đọc, cập nhật và xoá (CRUD) các quá trình vận hành và các phương thức HTTP. Theo cách ánh xạ này thì:
    • Để tạo một tài nguyên trên máy chủ, bạn cần sử dụng phương thức POST.
    • Để truy xuất một tài nguyên, sử dụng GET.
    • Để thay đổi trạng thái một tài nguyên hoặc để cập nhật nó, sử dụng PUT.
    • Để huỷ bỏ hoặc xoá một tài nguyên, sử dụng DELETE.
    Một lỗ hổng trong thiết kế vốn có trong các Web API là việc sử dụng các phương thức HTTP mà không có mục đích trước. Ví dụ lệnh URI trong một lệnh HTTP GET thường xác định một tài nguyên cụ thể. Hoặc một chuỗi truy vấn trong một lệnh URI bao gồm một nhóm các tham số xác định tiêu chí tìm kiếm được máy chủ sử dụng để tìm các tài nguyên phù hợp. Ít nhất điều này cho thấy HTTP/1.1 miêu tả GET như thế nào. Nhưng có nhiều trường hợp Web APIs không được tốt lắm, do sử dụng HTTP GET để khởi động một vài tác vụ trên máy chủ — ví dụ, thêm các bản ghi vào một cơ sở dữ liệu. Trong các trường hợp này, phương thức GET-yêu-cầu-URI đã không được sử dụng đúng đắn hoặc chưa sử dụng đầy đủ. Nếu Web API sử dụng GET để tiến hành các thủ tục ra lệnh từ xa thì nó sẽ có dạng như sau:

    GET /adduser?name=Robert HTTP/1.1
    Đây không phải là mẫu thiết kế hấp dẫn vì phương pháp nói trên hỗ trợ phương thức thay đổi trạng thái trên HTTP GET. Nói cách khác, phương thức yêu cầu HTTP GET nói trên có những tác động phụ. Nếu được xử lý thành công, kết quả của yêu cầu (trong ví dụ này) là để tạo thêm một người dùng mới vào kho dữ liệu. Vấn đề ở đây chỉ về mặt ngữ nghĩa. Các Web server được thiết kế để phản hồi lại các yêu cầu HTTP GET bằng cách truy vấn dữ liệu phù hợp với đường dẫn (hoặc câu truy vấn) theo URI và phản hồi những dữ liệu này hoặc những thông tin đại diện, chứ không phải để thêm một dữ liệu vào database. Từ góc độ mục đích sử dụng giao thức đó và theo tiêu chuẩn Web server HTTP/1.1 thì việc sử dụng GET theo cách này tồn tại mâu thuẫn.
    Về mặt ngữ nghĩa, có nhiều vấn đề khi sử dụng GET là để khởi động một sự xoá bỏ, sửa đổi, hoặc ghi thêm vào cơ sở dữ liệu, hoặc để thay đổi trạng thái máy chủ theo một cách nào đó. Nó dùng các công cụ Web cache (các đường dẫn) và các công cụ tìm kiếm để làm thay đổi máy chủ một cách không chủ định thông qua đường dẫn. Một cách đơn giản để vượt qua vấn đề hay xảy ra này là di chuyển tên và giá trị các tham số yêu cầu trên URI vào các thẻ XML. Các thẻ kết quả, một đại diện XML của một chủ thể được tạo ra, có thể được gửi vào một nhóm HTTP POST, những nơi mà yêu cầu URI là chủ thể sinh ra có chủ đích (xem ví dụ 1 và 2).
    Ví dụ 1. Trước
    GET /adduser?name=Robert HTTP/1.1
    Ví dụ 2. Sau
    POST /users HTTP/1.1
    Host: myserver
    Content-Type: application/xml
    <?xml version="1.0"?>
    <user>
      <name>Robert</name>
    </user>
    Phương pháp trên là ví dụ của yêu cầu RESTful: sử dụng đúng HTTP POST và bao gồm cả tải trọng trong phần thân câu lệnh. Đối với phía đầu tiếp nhận, câu lệnh có thể được xử lý bằng cách thêm tài nguyên vào hệ thống đó như một phần tài nguyên phụ được định dạng trong lệnh URI; trong trường hợp này tài nguyên mới phải được thêm vào như là một nhánh con của /users. Quan hệ bao hàm giữa thực thể mới và nhánh cha, như đã xác định trong yêu cầu POST, tương tự như cách tệp đã thuộc thư mục cha. Máy khách thiết lập quan hệ giữa thực thể và nhánh cha, và xác định URI của thực thể mới trong yêu cầu POST.
    Ứng dụng máy khách sau đó có thể nhận kết nối của nguồn sử dụng URI mới, lưu ý rằng ít nhất về mặt logic, nguồn được đặt dưới /users, như trong ví dụ 3.
    Ví dụ 3. Lệnh HTTP GET
    GET /users/Robert HTTP/1.1
    Host: myserver
    Accept: application/xml
    Sử dụng GET theo cách này rất rõ ràng vì GET chỉ dành cho truy cập dữ liệu. GET là một phương thức mà không có hiệu ứng phụ, như là một đặc tính riêng không thay đổi giá trị.
    Tương tự, những thay đổi của phương thức Web cũng cần được ứng dụng trong các trường hợp khi một thao tác cập nhật được hỗ trợ qua HTTP GET, như thể hiện trong ví dụ 4.
    Ví dụ 4. Thực hiện lệnh Cập nhật thông qua HTTP GET
    GET /updateuser?name=Robert&amp;newname=Bob HTTP/1.1
    Câu lệnh này thay đổi thuộc tính (hoặc đặc tính) name của dữ liệu. Có thể dùng chuỗi truy vấn (query) để dùng cho những thao tác như thế này, và ví dụ 4 là một ví dụ đơn giản, mẫu phương-pháp-dấu-hiệu-như-là-chuỗi-truy-vấn (query-string-as-method-signature) có thể không hoạt động khi sử dụng đối với các thao tác phức tạp hơn. Do mục tiêu của chúng ta là làm rõ việc sử dụng các phương thức HTTP, nên cách tiếp cận RESTful là gửi một yêu cầu HTTP PUT để cập nhật tài nguyên, thay vì HTTP GET, cho những lý do tương tự chỉ ra ở trên (xem ví dụ 5).
    Ví dụ 5. Lệnh HTTP PUT
    PUT /users/Robert HTTP/1.1
    Host: myserver
    Content-Type: application/xml
    <?xml version="1.0"?>
    <user>
      <name>Bob</name>
    </user>
    Sử dụng PUT để thay đổi dữ liệu gốc, cho thấy cách làm rõ ràng hơn, phù hợp với các nguyên lý của REST và các khái niệm của các phương thức HTTP. Lệnh PUT trong ví dụ 5 rõ ràng ở chỗ nó chỉ ra dữ liệu được cập nhật bằng cách xác định nó trong câu lệnh URI, và nó chuyển một đại diện mới của các thuộc tính dữ liệu cần chuyển đổi như là nhóm không chặt chẽ các tên tham số và giá trị trên lệnh URI. Ví dụ 5 cũng có hiệu ứng từ việc đổi tên tài nguyên từ Robert sang Bob, và trong việc các thay đổi của URI sang /users/Bob. Trong một dịch vụ mạng REST, lệnh tiếp theo của tài nguyên sử dụng URI cũ sẽ sinh ra lỗi căn bản 404 Not Found.
    Như là một nguyên tắc thiết kế chung, nó giúp theo sát các hướng dẫn sử dụng REST để sử dụng các phương pháp HTTP một cách rõ ràng bằng cách sử dụng các danh từ trong URIs thay vì động từ. Trong một Web service RESTful, các động từ — POST, GET, PUT, và DELETE — đã được định nghĩa bởi giao thức. Và tốt nhất, để giữ giao diện được khái quát hoá và cho phép người dùng hiểu rõ các thao tác mà họ gọi thì Web service không nên đưa ra nhiều động từ hoặc các thủ tục remote từ xa, như /adduser hoặc /updateuser. Nguyên tắc thiết kế chung này cũng áp dụng đối với phần thân câu lệnh HTTP, được sử dụng có chủ ý để chuyển trạng thái tài nguyên, không mang tên của một phương thức hay thủ tục 

    Phi trạng thái

    Các Web service REST cần được điều chỉnh về quy mô để đáp ứng được các yêu cầu ngày càng cao về chất lượng thực hiện. Các khu vực lưu trữ của máy chủ với khả năng cân bằng tải và vượt qua sự mất mát, các bức ngăn (tường lửa) và các cổng được sắp xếp theo một phương thức đặc thù nhằm tạo ra một cấu trúc dịch vụ bền vững cho phép chuyển tiếp yêu cầu từ một máy chủ tới máy chủ khác khi cần để giảm tổng thời gian phản hồi của một yêu cầu Web service. Sử dụng máy chủ trung gian nhằm nâng cao mức yêu cầu dịch vụ mạng REST của khách hàng để gửi các yêu cầu hoàn chỉnh và độc lập, có nghĩa là gửi các yêu cầu bao gồm tất cả dữ liệu cần thiết để đáp ứng sao cho các thành phần trong các máy chủ trung gian có thể gửi tiếp đi, gửi theo tuyến và cân bằng tải mà không cần các trạng thái được kiểm soát bên trong giữa các yêu cầu.
    Một yêu cầu hoàn chỉnh, độc lập không đòi hỏi máy chủ để thu thập được bất kỳ ngữ cảnh hoặc trạng thái của ứng dụng nào trong lúc xử lý yêu cầu. Một ứng dụng (hoặc máy khách) Web service RESTchứa ở phần đầu và phần thân trang HTTP của một yêu cầu tất cả các tham số, ngữ cảnh và dữ liệu cần thiết bởi thành phần bên ngoài máy chủ để đưa ra một phản hồi. Phi trạng thái theo nghĩa này nâng cao tính hiệu quả của dịch vụ Web, đơn giản hoá thiết kế và sự thi hành của các thành phần của máy chủ vì khi máy chủ không có trạng thái sẽ huỷ bỏ nhu cầu để đồng bộ hoá các mảng dữ liệu với một ứng dụng bên ngoài.
    Hình 1 minh hoạ một dịch vụ trạng thái, từ đó một ứng dụng có thể yêu cầu trang sau trong một tập hợp các trang kết quả, giả sử rằng dịch vụ theo sát ứng dụng dừng lại ở nơi trong khi điều chỉnh tập hợp đó. Đối với thiết kế trạng thái, dịch vụ gia tăng và lưu giữ một previousPage (trang trước) thay đổi ở nơi để có thể phản hồi các lệnh tiếp theo.
    Hình 1. Thiết kế trạng thái
    Thiết kế trạng thái
    Dịch vụ trạng thái như thế này trở nên phức tạp. Trong môi trường Nền tảng Java, Phiên bản Doanh nghiệp (EE), dịch vụ trạng thái yêu cầu rất cẩn thận lúc ban đầu để lưu trữ hiệu quả và cho phép đồng bộ hoá dữ liệu session (phiên làm việc) qua một hệ thống container Java EE. Trong môi trường này, có một vấn đề quen thuộc đối với các chuyên viên phát triển servlet/JavaServer Pages (JSP) và Enterprise JavaBeans (EJB), những người này thường gặp khó khăn khi tìm gốc rễ nguyên nhân của java.io.NotSerializableException trong khi tái tạo session. Liệu nó được chuyển bởi thành phần chứa Servlet trong khi HttpSession được tái tạo hoặc chuyển đi bởi thành phần chứa EJB trong khi sao bản EJB trạng thái, đó là vấn đề mà có thể làm các chuyên viên phát triển mất nhiều ngày để xác định mấu chốt một đối tượng mà không thực thiSerializable, đôi khi trong một đồ thị phức tạp của các đối tượng mà đóng góp nên trạng thái của máy chủ. Ngoài ra, phần tối ưu hoá làm đội thêm chi phí ảnh hưởng đến hiệu quả của máy chủ.
    Mặt khác, các thành phần máy chủ phi trạng thái ít phức tạp hơn để thiết kế, viết và phân bổ thông qua máy chủ được cân bằng tải. Dịch vụ phi trạng thái không chỉ hoạt động tốt hơn, nó còn chuyển hầu hết vai trò duy trì trạng thái sang ứng dụng ở máy khách. Trong một dịch vụ mạng RESTful, máy chủ chịu trách nhiệm đưa ra các phản hồi và cung cấp một giao diện cho phép máy khách duy trì trạng thái ứng dụng của chính nó. Ví dụ, trong yêu cầu tập hợp trang kết quả, máy khách sẽ gồm số trang thực tế khi truy xuất thay vì đơn giản chỉ là yêu cầu tiếp theo (xem hình 2).
    Hình 2. Thiết kế phi trạng thái
    Thiết kế phi trạng thái
    Một dịch Web phi trạng thái sinh ra một phản hồi liên kết với số trang tiếp theo trong một tổng thể và để máy khách làm những gì mà nó cần để giữ giá trị này ở mức nhất định. Khía cạnh này của thiết kế dịch vụ Web RESTful có thể được tách thành hai phần trách nhiệm như là mức phân chia cao nhất mà chỉ rõ một dịch vụ phi trạng thái có thể được duy trì như thế nào.
    Máy chủ
    • Tạo ra các phản hồi bao gồm các đường dẫn tới nguồn tài nguyên cho phép các ứng dụng điều hướng giữa các tài nguyên liên quan. Loại phản hồi này nhúng các liên kết. Tương tự, nếu các yêu cầu đối với máy chủ hoặc các kho tài nguyên, thì các phản hồi RESTful Web service điển hình có thể bao gồm các đường dẫn đến các máy con hoặc các tài nguyên phụ sao cho những phản hồi này được duy trì kết nối.
      Tạo ra các phản hồi mà xác định chúng có thể lưu trữ hoặc không phải để nâng cao được hiệu quả bằng cách giảm số lượng yêu cầu đối với các tài nguyên trùng nhau và bằng cách loại trừ một vài yêu cầu toàn bộ. Máy chủ làm được như vậy bằng cách gộp một phản hồi phần đầu HTTP Last - Modified (lần sửa gần nhất) (giá trị ngày) và Cache-Control (bộ điều khiển lưu trữ).

      Ứng dụng máy khách


      Sử dụng phần đầu phản hồi Cache-Control (bộ điều khiển lưu trữ tạm) để xác định lưu trữ tài nguyên (lập một vùng sao chép nội bộ) hay không. Máy khách cũng đọc phần đầu phản hồi Last-Modified (lần sửa gần nhất) và gửi lại giá trị ngày vào phần đầu If-Modified-Since (nếu-sửa) để truy vấn máy chủ xem tài nguyên có thay đổi không. Việc này được gọi là truy vấn có điều kiện, và hai phần đầu đi với nhau trong phản hồi của máy chủ là mã 304 chuẩn (không sửa đổi) và bỏ qua tài nguyên thực được yêu cầu nếu nó không thay đổi. Mã phản hồi HTTP 304 có nghĩa rằng máy khách có thể sử dụng an toàn một vùng sao lưu nội bộ, lưu giữ một bản sao mới nhất của tài nguyên đại diện, hiệu quả bằng cách vượt qua yêu cầu GET tiếp theo cho đến khi tài nguyên thay đổi.
      Gửi các yêu cầu hoàn chỉnh có thể được đáp ứng độc lập bởi các yêu cầu khác. Điều này đòi hỏi máy khách sử dụng toàn bộ các phần đầu HTTP như chỉ định bởi giao diện dịch vụ mạng và để gửi các đại diện tài nguyên hoàn chỉnh trong phần giữa của yêu cầu. Máy khách gửi yêu cầu lập một vài giả thuyết về các yêu cầu trước đó, sự tồn tại của một vùng của máy chủ, khả năng của máy chủ để thêm các ngữ cảnh vào yêu cầu, hoặc về các trạng thái ứng dụng mà được giữ giữa các yêu cầu.

      Sự hợp tác này giữa ứng dụng máy khách và máy chủ là cần thiết để có một phi trạng thái trong một Web service RESful. Nó nâng cao hiệu quả bằng cách tiết kiệm băng thông và tối thiểu hoá trạng thái ứng dụng về phía máy chủ.








































    Đưa ra cấu trúc thư mục giống URIs

    Từ điểm hiện có của tài nguyên địa chỉ ứng dụng máy khách, các đường dẫn xác định tính hiện thực của Web service REST như thế nào, và được sử dụng theo cách các chuyên viên thiết kế có thể tham gia. Tính năng thứ ba của Web service RESful về tất cả đường dẫn.
    Các địa chỉ Web service REST nên có tính hiện thực theo nghĩa rằng chúng dễ dàng đối với người dùng. Có thể nghĩ rằng một địa chỉ đường dẫn như là giao diện tự đóng gói mà đòi hỏi ít lý giải hoặc tham chiếu, nếu có, đối với một nhà phát triển để hiểu nó nhắm đến điểm gì và phân phát tài nguyên liên quan. Cuối cùng, cấu trúc của một địa chỉ nên rõ ràng, có thể đoán được và dễ hiểu.
    Một cách để đạt được mức độ sử dụng này là xác định cấu trúc thư mục giống URIs. Loại URI này có thứ bậc, có điểm khởi nguồn tại một đường dẫn đơn giản, và có nhánh đi ra là các nhánh phụ thể hiện các vùng chính của dịch vụ. Theo định nghĩa này, một URI không chỉ là một chuỗi bị cắt không giới hạn, mà còn là một cây với các nhánh chính và nhánh dọc nối với nhau tại các nút.
    Phần gốc, /discussion, có một nút /topics bên dưới nó. Phía dưới là một chuỗi tên các chủ đề, như chuyện xã hội, kỹ thuật, v.v.., mỗi chủ đề chỉ ra một mạch thảo luận. Trong cấu trúc này, dễ dàng kéo các mạch thảo luận bằng cách gõ một vài thứ sau /topics/.
    Trong một vài trường hợp, đường dẫn tới một tài nguyên cho mượn chính nó đặc biệt tốt với cấu trúc giống cây thư mục. Ví dụ, tài nguyên được cấu trúc bởi ngày, điều mà phối hợp rất tốt để sử dụng một cú pháp phân cấp.
    Phần đầu tiên trong đường dẫn là năm có bốn chữ số, phần thứ hai là ngày có hai chữ số, và phần thứ ba là tháng có hai chữ số. Có vẻ hơi ngu ngốc khi giải thích theo cách này, nhưng đây là mức độ đơn giản. Con người và máy móc có thể dễ dàng sinh ra các cấu trúc URIs giống như vậy vì chúng dựa trên các nguyên tắc. 
    Một vài hướng dẫn bổ sung để lưu ý trong khi nói về cấu trúc địa chỉ của Web service RESTful là:
    • Giấu các đuôi tài liệu mở rộng của bản gốc trong máy chủ (.jsp, .php, .asp), nếu có, vì vậy bạn có thể giấu một số thứ mà không cần thay đổi địa chỉ Urls.
    • Để mọi thứ là chữ thường.
    • Thay thế các khoảng trống bằng gạch chân hoặc hoặc gạch nối (một trong hai loại).

    • Tránh các chuỗi yêu cầu càng nhiều càng tốt.
    • Thay vì sử dụng mã (404 Not Found) khi yêu cầu địa chỉ cho một phần đường dẫn, luôn luôn cung cấp một trang mặc định hoặc tài nguyên như một phản hồi.
    Các địa chỉ URIs nên giữ nguyên để khi tài nguyên thay đổi hoặc khi tiến hành thay đổi dịch vụ, đường liên kết cũng sẽ giữ nguyên. Việc này cho phép đánh dấu lại vị trí đang đọc. Nó cũng rất quan trọng vì mối liên quan giữa các tài nguyên mà được mã hoá trong các địa chỉ được giữ nguyên độc lập với các mối liên quan đại diện khi chúng được lưu trữ.

    Chuyển đổi XML, JSON, hoặc cả hai

    Một tài nguyên đại diện điển hình phản ánh trạng thái hiện tại của một tài nguyên, và các thuộc tính của nó, tại thời điểm một ứng dụng máy khách yêu cầu nó. Các đại diện tài nguyên theo nghĩa này là chỉ các bản tóm tắt lúc đó. Điều này có thể đơn giản như một đại diện của một bản ghi trong một cơ sở dữ liệu, bao gồm một tổng thể giữa tên các cột và các thẻ XML, nơi các giá trị thành phần trong XML bao gồm các giá trị dòng. Hoặc nếu hệ thống có một mô hình dữ liệu, thì theo định nghĩa này một tài nguyên đại diện là một bản tóm tắt các thuộc tính của những thứ trong mô hình dữ liệu hệ thống. Đây là những điều bạn muốn Web services REST mang đến.
    Những trở ngại cuối cùng, đi kèm với thiết kế Web service RESTful, phải làm với định dạng dữ liệu mà ứng dụng và trao đổi dịch vụ trong mức đáp ứng yêu cầu/phản hồi hoặc trong phần thân của HTTP. Đây chính là điều nó làm để giữ mọi thứ đơn giản, có thể đọc được và kết nối được.
    Các chủ thể trong mô hình dữ liệu của bạn thường liên quan đến nhau theo cách nào đó, và mối liên hệ giữa mô hình dữ liệu chủ thể (tài nguyên) nên được phản ánh theo cách chúng được đại diện để chuyển đến một ứng dụng máy khách. Trong dịch vụ chuỗi thảo luận, một ví dụ của đại diện tài nguyên được kết nối có thể bao gồm một chủ đề thảo luận gốc và các thuộc tính của nó, và các đường dẫn được nhúng vào các phản hồi nhất định của chủ đề đó.
    Ví dụ 6. Đại diện XML của một chuỗi thảo luận
    <?xml version="1.0"?>
    <discussion date="{date}" topic="{topic}">
      <comment>{comment}</comment>
      <replies>
        <reply from="joe@mail.com" href="/discussion/topics/{topic}/joe"/>
        <reply from="bob@mail.com" href="/discussion/topics/{topic}/bob"/>
      </replies>
    </discussion>
    Cuối cùng, để đưa đến khả năng yêu cầu loại nội dung cụ thể cho các ứng dụng máy khách mà phù hợp nhất với chúng, hãy cấu trúc dịch vụ của bạn sao cho nó tận dụng được phần đầu chấp nhận HTTP sẵn có bên trong, nơi giá trị của phần đầu là một loại MIME. Một vài loại MIME thông thường được sử dụng bởi dịch vụ RESTful được thể hiện trong Bảng 1.
    Bảng 1. Loại MIME phổ biến được sử dụng bởi dịch vụ RESTful
    MIME-TypeContent-Type
    JSONapplication/json
    XMLapplication/xml
    XHTMLapplication/xhtml+xml
    Nó cho phép dịch vụ được nhiều khách hàng khác nhau sử dụng, viết bằng các ngôn ngữ khác nhau, chạy trên nền và thiết bị khác nhau. Sử dụng kiểu MIME và phần đầu HTTP Accept là một cơ chế được biết như là nội dung thương thuyết, cái mà cho phép máy khách chọn định dạng dữ liệu nào là đúng với chúng và tối thiểu hoá sự nối lại giữa dịch vụ và các ứng dụng mà sử dụng nó.

    Kết luận

    REST không phải là sự lựa chọn luôn đúng. Đã có trường hợp khi thiết kế Web service, nó có sự kém độc lập đối với phần mềm trung gian (ví dụ: một ứng dụng máy chủ) so với loại dựa trên SOAP hặc WSDL. Có nghĩa REST là một sự quay lại con đường mạng trước thời đại ứng dụng máy chủ rất lớn, kể cả ấn tượng các chuẩn của internet thời kỳ đầu, địa chỉ và HTTP. Bạn vừa nghiên cứu nguyên tắc gọi là thiết kế giao diện RESTful, XML so với HTTP là một giao diện vượt trội cho phép các ứng dụng bên trong, như các giao diện người dùng dựa trên Asynchronous JavaScript + XML (Ajax), dễ dàng kết nối, xác định, và tiêu thụ tài nguyên. Thực tế, sự tương thích lớn giữa Aax và REST đã nhận được rất nhiều sự chú ý gần đây.
    Đưa một tài nguyên hệ thống thông qua một RESTful API là một cách linh động để cung cấp các loại ứng dụng khác nhau với dữ liệu đã được định dạng theo cách tiêu chuẩn. Nó giúp đáp ứng các yêu cầu tích hợp, điều rất quan trọng để xây dựng hệ thống khi dữ liệu được kết hợp dễ dàng (mashups) và để mở rộng hoặc xây dựng trên một gói hệ thống căn bản. Dịch vụ RESTful có thể rất lớn đối với một số thứ. Bài viết này hướng dẫn dựa vào nguyên lý cơ bản trên và hy vọng bằng cách nào đó sẽ khuyến khích bạn khám phá chủ đề này.

    Tài nguyên

    Học tập

    Lấy sản phẩm và công nghệ


    Thảo luận

    • Tham gia vào cộng đồng các chuyên viên phát triển bằng cách gia nhập vào developerWorks blogs.