preface

Nice to meet you

Cookies were added in HTTP1.1 to address the stateless nature of HTTP by making it “stateful.”

When we are doing Android development, the existence value and optimization of cookies are often not well understood. This is actually normal. Http (Hypertext Transfer Protocol) is a transport protocol for Web development. As one of the functions of cookie, his design naturally serves the Web. To better understand cookie’s nature, you need to understand it from the perspective of Web development, specifically materializing the client using a browser web page.

Android came much later than the Web. Although both use cookies, cookies don’t have the same benefits over Android as the Web. But cookies are not completely useless. For example, we all know that cookies can be used to remember login status.

The purpose of this article is to help Android developers understand the nature of cookies so that we can be more confident when using them.

Shopping Cart Story

As we all know, HTTP is a stateless protocol. Statelessness means that each request and response are independent and do not record or affect each other.

Huh? Don’t we maintain the state of the shopping cart on the back end and provide apis to the customer? Yes, we can, and we can use data structures on the back end to store shopping cart information. But that’s not HTTP. You can’t do that with HTTP alone, can you? Each HTTP request is independent and does not affect each other; he does not remember what was sent or returned during the last visit.

To remember the state of the operation, HTTP designers attach some information to the request header that identifies our state of the operation:

Each time the client manipulates the shopping cart, the server generates a field for it and sends this field to the client. This field stores the previous operation state of the client. The next time the client requests the server, it only needs to attach this field to the request header. The server can understand what the previous request has done by parsing the contents of this field.

For example, in the figure above, when the client adds an orange, the server generates [orange=1] and plays it to the client for storage. The client’s next operation simply appends orange=1 to the request header, and the server knows that the client has added an orange to the cart.

It’s obvious by now that this field is a cookie.

Cookies are generated by the server and stored in the client. Each time the client requests to attach the cookie, the server realizes the state record by parsing the content of the cookie.

The whole cookie mechanism, the client to do a simple thing: store cookies, attach cookies. The client does not participate in cookie generation or cookie modification. The server is responsible for generating and parsing cookies, but not for storing them.

The realization of the cookie

Cookies are implemented in HTTP through two header fields: cookie and set-cookie.

Set-cookie is attached to the response packet to inform the client that the cookie needs to be stored. For example, the set – cookies: orange = 1. Cookie is a field in the header of a request packet. The cookie is generated by the server, for example, Orange =1.

SequenceDiagram Client ->> Server: Add an orange server -->> Client: set-cookie: orange=1 Client ->> Server: cookie: orange=1, add two bananas server -->> Client: The set - cookies: orange = 1 & bananer = 2

In the cookie mechanism, both the client and the server must play their respective roles.

  • The client, specifically the browser, automatically stores the cookies generated by a website, and the next request automatically appends the cookies to the request header.
  • The server, upon receiving the cookie field, needs to automatically parse and respond to the corresponding result. Orange =1 + bananer=2 + orange=1 + bananer=2

At the same time, cookies can have multiple, that is, there can be more than one cookie, so that a website can use cookies to record multiple states at the same time. Here we use Postman to look at baidu’s cookies:

As you can see, Baidu returned up to 6 set-cookies. In addition, we can view the cookies of a website through the browser:

You can see that baidu uses up to 37 cookies. Click the cookie to view the specific content.

It should also be noted that cookies are generally encrypted rather than transmitted in plaintext over the network. This was very important in the early days without HTTPS, otherwise any node in the network could hijack our cookies. The set-cookie field of Baidu website in Postman above can be clearly seen to be encrypted.

Let’s take a look at two more examples to further understand cookies.

Theme preference

Some sites have a feature that doesn’t require you to log in, but allows you to remember your chosen theme, such as dark or light colors. The next visit is still our last choice. We could certainly choose the results for each IP and port record on the back end, but the increasing number of visits takes up a lot of space and affects query performance. This is where cookies come in, and they are a much more lightweight way to do this. Its functional model is shown below:

SequenceDiagram Client ->> Server: Set dark theme server ->> Client: set-cookie: theme=dark client ->> Server: cookie: theme=dark server ->> Client: Return dark theme web page

When we set the theme, the server will generate a theme preference cookie for us to store. The next time you attach a cookie to the request header, the server parses the cookie and returns the page with the corresponding topic. Is this lighter and simpler than using data structures on the server to store user information? And you don’t need to log in to remember your theme preferences.

This might not seem very useful on Android because our themes are configured locally and the interface design content is stored locally, so there is no need for the server to remember theme preferences for us.

But from a Web perspective, it’s very useful. The specific content of the web page is stored on the server, and the browser is only responsible for rendering the interface. At this time, I need cookies to tell the server, what theme I selected last time, this time you also return to me the same theme of the webpage interface.

Remember login status

Hey, sign in, we Android engineers, it’s easy to understand. After all, the first time I come into contact with cookies may be to use them to remember the login status, which is the case with the author. Of course, in commercial projects, due to the insecure design of cookies, they will not be used as a means to remember the login status, which is a more specific content of login registration. Let’s take a look at how cookies are implemented to remember login status:

SequenceDiagram Client ->> Server: user= Admin&Password =123123 Server ->> Client: set-cookie: sessionId=ABC123 Client ->> Server: Cookie: sessionId=ABC123 Server -->> client: returns dark theme web page
  1. When we access the server and log in, the server creates a session for us, a session.
  2. The server returns the sessionId in a cookie.
  3. The server appends the cookie to the request header the next time it requests the server.
  4. By parsing the sessionId and finding the corresponding session, the server knows that we have logged in and can identify ourselves, because our login information is recorded in the session.

There’s another convenient but less secure way to remember your login: simply encrypt your user name and password and store it in a cookie for the browser to store. This is very simple and crude, for the encryption algorithm is relatively high requirements. Cookies of this type usually have an expiration date, after which you must log in again.

In the Context of the Web, using cookies to remember login is still not secure, so let’s take a look at some of the disadvantages of cookies.

The disadvantage of the cookie

The disadvantage of cookie lies in its automatic feature. Whether the browser automatically stores and attaches cookies, or the server automatically recognizes cookies and responds directly, it is not safe. Let me give you a couple of examples.

Consider a bank website that uses cookies to record login status. When we visit the attacker’s website, the js script of the website can directly access the bank’s transfer interface. The browser will automatically help us to attach the cookie of the bank website, and the bank server will parse it into our cookie, judge the login, and directly transfer the money.

For example, after the local JS script gets our stored cookies, it can replace our identity to visit various websites. As above, once the server sees the cookie, it determines that it is us.

In addition, issues such as Web bugs also lead to privacy breaches — simply storing information about websites we visit in cookies and asking a server that can parse the cookies to gather information about our browsing and deliver targeted ads to us. This program is also commonly used as browser behavior tracking, within the legal scope to help improve the quality of our network service, but inevitably there will be lawbreakers to complete some bad operations.

Some optimizations have been made to address these shortcomings. For example, if the httpOnly header is set in the response packet, the local JS script cannot get the cookie, thus ensuring security. However, this feature requires browser cooperation, and if the browser does not have this implementation, it is still not secure.

But these shortcomings are naturally safe in the Android environment. Because our app will not be implanted with script code, there is no other program to get cookies.

Use in Android

To be clear, client operations on cookies are limited. We only need to take care of two things: storing cookies on the site and attaching them to requests.

It is important to note that the cookies of different websites need to be separated. Do not write logic to attach all cookies every time. But for your own app, which usually only has your own server at the back end, this is relatively unimportant.

OkHttp is commonly used in the web framework developed by Android. Here is how to use okHttp to perform cookie operations. The okHttp framework does not implement cookie storage by default. If you need to manipulate cookies, there are two ways: use okHttp’s cookie storage interface and use an interceptor.

Use the cookie storage interface

OkHttp provides an interface that makes it easy to do cookies. We can do this by calling the okHttpClient method as follows:

val okHttpBuilder = OkHttpClient.Builder()
okHttpBuilder.apply {
    cookieJar(object : CookieJar{
                override fun saveFromResponse(url: HttpUrl, cookies: MutableList<Cookie>) {
                    // Implement the logic to store cookies
                }
                override fun loadForRequest(url: HttpUrl): MutableList<Cookie> {
                    // Implement the logic to add cookies}})}Copy the code

The CookieJar is an interface that has two methods for storing and adding cookies. When it receives a response, okHttp takes out the cookie in the response header and calls back saveFromResponse. When a request is made, loadForRequest is called to return a list of cookies to be added to the request header.

So we just need to set the cookie callback listening when we create the OkHttpClient.

It is important to note that whether you use OkHttp directly or Retrofit, try to keep the OkHttpClient global singleton so that the configured cookie logic is not invalidated. Retrofit can customize okHttpClient by:

mRetrofit = Retrofit.Builder()
            .client(okHttpBuilder.build())
            .baseUrl(BASE_URL)
            .build()
Copy the code

Use interceptors

OkHttp goes through a series of interceptors before sending a request. Interceptors can be simply defined as each request sent through the interceptor we configured and returned through the interceptor we configured. So that we can intercept the request at the time of the request and then send the cookie; Then, when responding, the cookie is removed and the response message is returned. The following code:

class CookieInterceptor() :Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val requestBuilder = chain.request().newBuilder()
        // Add cookies to the request
        addCookie(requestBuilder)
        // Execute the request
        var response = chain.proceed(requestBuilder.build())
        // Stores cookies for the response
        storeCookie(response)
        return response
    }
}
Copy the code

Request is our request in the code. After calling proceed, the request will be initiated and the response will be obtained. After that, we will remove the cookie from the RESP and return the response. AddCookie and storeCookie methods need to be implemented by ourselves, the specific implementation is more flexible, Room, SharePreference are ok.

Then configure the client to add interceptors:

val okHttpBuilder = OkHttpClient.Builder()
okHttpBuilder.apply {
    addInterceptor(CookieInterceptor()))
}
Copy the code

Here we add a custom interceptor for OkHttpClient.

This approach is a little more complicated than the first direct use of the cookieJar, but the interceptor can do a lot more and is more flexible. Interceptors can modify the entire contents of a request, such as if I redirected baidu.com to Google.com. Interceptors can do this, but the cookieJar only stores cookies.

The interceptor aspect will not be expanded, but interested readers can take a closer look.

The last

A lot of things that relate to HTTP are designed to some extent for the Web side. If you feel foggy when you’re studying, maybe it’s the wrong way to open it. Knowing a little bit about the front end, understanding it from a Web perspective and applying it to Android development, is a much better posture.

The function of cookie still needs to cooperate with the back end. Cookie itself is only a field generated by the server, stored by the client, automatically attached and parsed. What functionality is built on top of that is up to the developer.

This knowledge of cookies is certainly not enough for the front end, but it is enough for Android engineers to handle normal business development.

Jin SAN Yin Si, we are all in spring recruitment recently, then I wish you can go ashore smoothly, get the offer of your favorite big factory.

If the article is helpful, I hope I can give a thumbs-up to encourage the author ~

Full text here, the original is not easy, feel help can like collection comments forward. Any ideas are welcome in the comments section.

If need to reprint please comment area or private letter to inform.

And welcome to my blog: Portal