Arabic, Egypt (ar-rEG) —————————–阿拉伯语,埃及
Arabic, Israel (ar-rIL) ——————————-阿拉伯语,以色列
Bulgarian, Bulgaria (bg-rBG) ———————保加利亚语,保加利亚
Catalan, Spain (ca-rES) —————————加泰隆语,西班牙
Czech, Czech Republic (cs-rCZ) —————–捷克语,捷克共和国
Danish, Denmark(da-rDK) ————————丹麦语,丹麦
German, Austria (de-rAT) ————————-德语,奥地利
German, Switzerland (de-rCH) ——————-德语,瑞士
German, Germany (de-rDE) ———————-德语,德国
German, Liechtenstein (de-rLI) ——————德语,列支敦士登的
Greek, Greece (el-rGR) —————————-希腊语,希腊
English, Australia (en-rAU) ————————-英语,澳大利亚
English, Canada (en-rCA) ————————–英语,加拿大
English, Britain (en-rGB) —————————-英语,英国
English, Ireland (en-rIE) —————————–英语,爱尔兰
English, India (en-rIN) ——————————–英语,印度
English, New Zealand (en-rNZ) ———————英语,新西兰
English, Singapore(en-rSG) ————————–英语,新加坡
English, US (en-rUS) ———————————–英语,美国
English, Zimbabwe (en-rZA) ————————–英语,津巴布韦
Spanish (es-rES) —————————————-西班牙
Spanish, US (es-rUS) ———————————–西班牙语,美国
Finnish, Finland (fi-rFI) ———————————芬兰语,芬兰
French, Belgium (fr-rBE) ——————————-法语,比利时
French, Canada (fr-rCA) ——————————-法语,加拿大
French, Switzerland (fr-rCH) ————————–法语,瑞士
French, France (fr-rFR) ——————————–法语,法国
Hebrew, Israel (he-rIL) ———————————希伯来语,以色列
Hindi, India (hi-rIN) ————————————-印地语,印度
Croatian, Croatia (hr-rHR) —————————-克罗地亚语,克罗地亚
Hungarian, Hungary (hu-rHU) ————————匈牙利语,匈牙利
Indonesian, Indonesia (id-rID) ————————印尼语,印尼
Italian, Switzerland (it-rCH) —————————-意大利语,瑞士
Italian, Italy (it-rIT) —————————————意大利语,意大利
Japanese (ja-rJP) —————————————-日语
Korean (ko-rKR) ——————————————朝鲜语
Lithuanian, Lithuania (lt-rLT) ————————–立陶宛语,立陶宛
Latvian, Latvia (lv-rLV) ———————————拉托维亚语,拉托维亚
Norwegian-Bokmol, Norway(nb-rNO) —————挪威语,挪威
Dutch, Belgium (nl-rBE) ——————————–荷兰语,比利时
Dutch, Netherlands (nl-rNL) —————————荷兰语,荷兰
Polish (pl-rPL) ——————————————-波兰
Portuguese, Brazil (pt-rBR) —————————葡萄牙语,巴西
Portuguese, Portugal (pt-rPT) ————————葡萄牙语,葡萄牙
Romanian, Romania (ro-rRO) ————————罗马尼亚语,罗马尼亚
Russian (ru-rRU) —————————————-俄语
Slovak, Slovakia (sk-rSK) ——————————斯洛伐克语,斯洛伐克
Slovenian, Slovenia (sl-rSI) —————————-斯洛文尼亚语,斯洛文尼亚
Serbian (sr-rRS) —————————————-塞尔维亚语
Swedish, Sweden (sv-rSE) —————————-瑞典语,瑞典
Thai, Thailand (th-rTH) ——————————–泰语,泰国
Tagalog, Philippines (tl-rPH) ————————–菲律宾语,菲律宾
Turkish, Turkey (tr-rTR) ——————————-土耳其语,土耳其
Ukrainian, Ukraine (uk-rUA) ————————–联合王国
Vietnamese, Vietnam (vi-rVN) ———————–越南语,越南
Chinese, PRC (zh-rCN)——————————–中文,中国
Chinese, Taiwan (zh-rTW)—————————–中文,台湾
Deployer 使用资料
A deployment tool for PHP
https://learnku.com/articles/10985/deployer-real-experience-sharing
How To Redirect www To non-www And Vice Versa with Nginx
In this short tutorial I’ll show you how to make permanent redirect from a www URL to non-www and vice versa. I’ll assume that you have superuser privileges, sudo or root access and Nginx already configured, as well as DNS records. More specifically, you need to have an A records for www.yourdomain.com and yourdomain.com .
Redirect non-www to www
To redirect users from a plain, non-www domain to a www domain, you need to add this snippet in your Nginx domain configuration file:
1 | server { |
Save your configuration and exit. Before restarting Nginx make sure to test your configuration:
1 | root@secure:~# nginx -t |
You should have something like this as output:
1 | root@secure:~# nginx -t |
Now when everything is checked you can restart Nginx:
1 | root@secure:~# service nginx restart |
Now, if you curl your plain domain, you should get a 301 Moved Permanently response:
1 | root@secure:~# curl -I yourdomain.dev |
Redirect www to non-www
In the previous example you saw how to redirect users from a plain non-ww domain to a www domain. However, if you want to redirect from a www to a plain non-www domain you need to add following snippet in your domain configuration file:
1 | server { |
After any change in Nginx configuration files you should test it for syntax errors:
1 | root@secure:~# nginx -t |
And if you curl the www domain you should get same 301 Moved Permanently response:
1 | root@secure:~# curl -I www.yourdomain.dev |
And that’s it. You have properly configured permanent redirect.
REFERENCES:
Nginx rewrite non-www-prefixed domain to www-prefixed domain
Nginx config for www to non-www and non-www to www redirection
How To Redirect www to Non-www with Nginx on CentOS 7
来源:
https://bosnadev.com/2015/06/26/how-to-redirect-www-to-non-www-and-vice-versa-with-nginx/
【转】Working with JSON in MySQL
SQL databases tend to be rigid.
If you have worked with them, you would agree that database design though it seems easier, is a lot trickier in practice. SQL databases believe in structure, that is why it’s called structured query language.
On the other side of the horizon, we have the NoSQL databases, also called schema-less databases that encourage flexibility. In schema-less databases, there is no imposed structural restriction, only data to be saved.
Table of Contents
- Why Use JSON
- The Schema
- The CRUD Operations
- A Primer for Web Applications
- Creating the Migrations
- Creating the Models
- Resource Operations
- Curtains
Though every tool has it’s use case, sometimes things call for a hybrid approach.
What if you could structure some parts of your database and leave others to be flexible?
MySQL version 5.7.8 introduces a JSON data type that allows you to accomplish that.
In this tutorial, you are going to learn.
- How to design your database tables using JSON fields.
- The various JSON based functions available in MYSQL to create, read, update, and delete rows.
- How to work with JSON fields using the Eloquent ORM in Laravel.
Why Use JSON
At this moment, you are probably asking yourself why would you want to use JSON when MySQL has been catering to a wide variety of database needs even before it introduced a JSON data type.
The answer lies in the use-cases where you would probably use a make-shift approach.
Let me explain with an example.
Suppose you are building a web application where you have to save a user’s configuration/preferences in the database.
Generally, you can create a separate database table with the id, user_id, key, and value fields or save it as a formatted string that you can parse at runtime.
However, this works well for a small number of users. If you have about a thousand users and five configuration keys, you are looking at a table with five thousand records that addresses a very small feature of your application.
Or if you are taking the formatted string route, extraneous code that only compounds your server load.
Using a JSON data type field to save a user’s configuration in such a scenario can spare you a database table’s space and bring down the number of records, which were being saved separately, to be the same as the number of users.
And you get the added benefit of not having to write any JSON parsing code, the ORM or the language runtime takes care of it.
The Schema
Before we dive into using all the cool JSON stuff in MySQL, we are going to need a sample database to play with.
So, let’s get our database schema out of the way first.
We are going to consider the use case of an online store that houses multiple brands and a variety of electronics.
Since different electronics have different attributes(compare a Macbook with a Vacuumn Cleaner) that buyers are interested in, typically the Entity–attribute–value model (EAV) pattern is used.
However, since we now have the option to use a JSON data type, we are going to drop EAV.
For a start, our database will be named e_store and has three tables only named, brands, categories, and products respectively.
Our brands and categories tables will be pretty similar, each having an id and a name field.
1 | CREATE DATABASE IF NOT EXISTS `e_store` |
The objective of these two tables will be to house the product categories and the brands that provide these products.
While we are at it, let us go ahead and seed some data into these tables to use later.
1 | /* Brands */ |
Next, is the business area of this tutorial.
We are going to create a products table with the id, name, brand_id, category_id, and attributes fields.
1 | CREATE TABLE `e_store`.`products`( |
Our table definition specifies foreign key constraints for the brand_id and category_id fields, specifying that they reference the brands and categories table respectively. We have also specified that the referenced rows should not be allowed to delete and if updated, the changes should reflect in the references as well.
The attributes field’s column type has been declared to be JSON which is the native data type now available in MySQL. This allows us to use the various JSON related constructs in MySQL on our attributes field.
Here is an entity relationship diagram of our created database.
Our database design is not the best in terms of efficiency and accuracy. There is no price column in the
productstable and we could do with putting a product into multiple categories. However, the purpose of this tutorial is not to teach database design but rather how to model objects of different nature in a single table using MySQL’s JSON features.
The CRUD Operations
Let us look at how to create, read, update, and delete data in a JSON field.
Create
Creating a record in the database with a JSON field is pretty simple.
All you need to do is add valid JSON as the field value in your insert statement.
1 | /* Let's sell some televisions */ |
Instead of laying out the JSON object yourself, you can also use the built-in JSON_OBJECT function.
The JSON_OBJECT function accepts a list of key/value pairs in the form JSON_OBJECT(key1, value1, key2, value2, ... key(n), value(n)) and returns a JSON object.
1 | /* Let's sell some mobilephones */ |
Notice the JSON_ARRAY function which returns a JSON array when passed a set of values.
If you specify a single key multiple times, only the first key/value pair will be retained. This is called normalizing the JSON in MySQL’s terms. Also, as part of normalization, the object keys are sorted and the extra white-space between key/value pairs is removed.
Another function that we can use to create JSON objects is the JSON_MERGE function.
The JSON_MERGE function takes multiple JSON objects and produces a single, aggregate object.
1 | /* Let's sell some cameras */ |
There is a lot happening in these insert statements and it can get a bit confusing. However, it is pretty simple.
We are only passing objects to the JSON_MERGE function. Some of them have been constructed using the JSON_OBJECT function we saw previously whereas others have been passed as valid JSON strings.
In case of the JSON_MERGE function, if a key is repeated multiple times, it’s value is retained as an array in the output.
A proof of concept is in order I suppose.
1 | /* output: {"network": ["GSM", "CDMA", "HSPA", "EVDO"]} */ |
We can confirm all our queries were run successfully using the JSON_TYPE function which gives us the field value type.
1 | /* output: OBJECT */ |
Read
Right, we have a few products in our database to work with.
For typical MySQL values that are not of type JSON, a where clause is pretty straight-forward. Just specify the column, an operator, and the values you need to work with.
Heuristically, when working with JSON columns, this does not work.
1 | /* It's not that simple */ |
When you wish to narrow down rows using a JSON field, you should be familiar with the concept of a path expression.
The most simplest definition of a path expression(think JQuery selectors) is it’s used to specify which parts of the JSON document to work with.
The second piece of the puzzle is the JSON_EXTRACT function which accepts a path expression to navigate through JSON.
Let us say we are interested in the range of televisions that have atleast a single USB and HDMI port.
1 | SELECT |
The first argument to the JSON_EXTRACT function is the JSON to apply the path expression to which is the attributes column. The $ symbol tokenizes the object to work with. The $.ports.usb and $.ports.hdmi path expressions translate to “take the usb key under ports” and “take the hdmi key under ports” respectively.
Once we have extracted the keys we are interested in, it is pretty simple to use the MySQL operators such as > on them.
Also, the JSON_EXTRACT function has the alias -> that you can use to make your queries more readable.
Revising our previous query.
1 | SELECT |
Update
In order to update JSON values, we are going to use the JSON_INSERT, JSON_REPLACE, and JSON_SET functions. These functions also require a path expression to specify which parts of the JSON object to modify.
The output of these functions is a valid JSON object with the changes applied.
Let us modify all mobilephones to have a chipset property as well.
1 | UPDATE `e_store`.`products` |
The $.chipset path expression identifies the position of the chipset property to be at the root of the object.
Let us update the chipset property to be more descriptive using the JSON_REPLACE function.
1 | UPDATE `e_store`.`products` |
Easy peasy!
Lastly, we have the JSON_SET function which we will use to specify our televisions are pretty colorful.
1 | UPDATE `e_store`.`products` |
All of these functions seem identical but there is a difference in the way they behave.
The JSON_INSERT function will only add the property to the object if it does not exists already.
The JSON_REPLACE function substitutes the property only if it is found.
The JSON_SET function will add the property if it is not found else replace it.
Delete
There are two parts to deleting that we will look at.
The first is to delete a certain key/value from your JSON columns whereas the second is to delete rows using a JSON column.
Let us say we are no longer providing the mount_type information for cameras and wish to remove it for all cameras.
We will do it using the JSON_REMOVE function which returns the updated JSON after removing the specified key based on the path expression.
1 | UPDATE `e_store`.`products` |
For the second case, we also do not provide mobilephones anymore that have the Jellybean version of the Android OS.
1 | DELETE FROM `e_store`.`products` |
As stated previously, working with a specific attribute requires the use of the JSON_EXTRACT function so in order to apply the LIKE operator, we have first extracted the os property of mobilephones(with the help of category_id) and deleted all records that contain the string Jellybean.
A Primer for Web Applications
The old days of directly working with a database are way behind us.
These days, frameworks insulate developers from lower-level operations and it almost feels alien for a framework fanatic not to be able to translate his/her database knowledge into an object relational mapper.
For the purpose of not leaving such developers heartbroken and wondering about their existence and purpose in the universe, we are going to look at how to go about the business of JSON columns in the Laravel framework.
We will only be focusing on the parts that overlap with our subject matter which deals with JSON columns. An in-depth tutorial on the Laravel framework is beyond the scope of this piece.
Creating the Migrations
Make sure to configure your Laravel application to use a MySQL database.
We are going to create three migrations for brands, categories, and products respectively.
1 | $ php artisan make:migration create_brands |
The create_brands and create_categories migrations are pretty similar and and a regulation for Laravel developers.
1 | /* database/migrations/create_brands.php */ |
The create_products migration will also have the directives for indexes and foreign keys.
1 | /* database/migrations/create_products */ |
Pay attention to the $table->json('attributes'); statement in the migration.
Just like creating any other table field using the appropriate data type named method, we have created a JSON column using the json method with the name attributes.
Also, this only works for database engines that support the JSON data type.
Engines, such as older versions of MySQL will not be able to carry out these migrations.
Creating the Models
Other than associations, there is not much needed to set up our models so let’s run through them quickly.
1 | /* app/Brand.php */ |
Again, our Product model needs a special mention.
The $casts array which has the key attributes set to array makes sure whenever a product is fetched from the database, it’s attributes JSON is converted to an associated array.
We will see later in the tutorial how this facilitates us to update records from our controller actions.
Resource Operations
Creating a Product
Speaking of the admin panel, the parameters to create a product maybe coming in through different routes since we have a number of product categories. You may also have different views to create, edit, show, and delete a product.
For example, a form to add a camera requires different input fields than a form to add a mobilephone so they warrant separate views.
Moreover, once you have the user input data, you will most probabaly run it through a request validator, separate for the camera, and the mobilephone each.
The final step would be to create the product through Eloquent.
We will be focusing on the camera resource for the rest of this tutorial. Other products can be addressed using the code produced in a similar manner.
Assuming we are saving a camera and the form fields are named as the respective camera attributes, here is the controller action.
1 | // creates product in database |
Fetching Products
Recall the $casts array we declared earlier in the Product model. It will help us read and edit a product by treating attributes as an associative array.
1 | // fetches a single product |
Your view would use the $camera variable in the following manner.
1 | <table> |
Editing a Product
As shown in the previous section, you can easily fetch a product and pass it to the view, which in this case would be the edit view.
You can use the product variable to pre-populate form fields on the edit page.
Updating the product based on the user input will be pretty similar to the store action we saw earlier, only that instead of creating a new product, you will fetch it first from the database before updating it.
Searching Based on JSON Attributes
The last piece of the puzzle that remains to discuss is querying JSON columns using the Eloquent ORM.
If you have a search page that allows cameras to be searched based on their specifications provided by the user, you can do so with the following code.
1 | // searches cameras by user provided specifications |
The retrived records will now be available to the product.camera.search view as a $cameras collection.
Deleting a Product
Using a non-JSON column attribute, you can delete products by specifying a where clause and then calling the delete method.
For example, in case of an ID.
1 | \App\Product::where('id', $id)->delete(); |
For JSON columns, specify a where clause using a single or multiple attributes and then call the delete method.
1 | // deletes all cameras with the sensor_type attribute as CMOS |
Curtains
We have barely scratched the surface when it comes to using JSON columns in MySQL.
Whenever you need to save data as key/value pairs in a separate table or work with flexible attributes for an entity, you should consider using a JSON data type field instead as it can heavily contribute to compressing your database design.
If you are interested in diving deeper, the MySQL documentation is a great resource to explore JSON concepts futher.
来源:
Oracle对where条件中有null值字段的处理
假如有如下数据(Users):
| ID | NAME | IS_ADMIN |
|---|---|---|
| 10000 | 贺一 | 是 |
| 10001 | 贺二 | |
| 10002 | 贺三 |
查询 admin:
1 | select * from users where is_admin = '是'; |
查询不是 admin:
如果使用下面的 sql, 查不到任何数据
1 | select * from users where is_admin != '是'; |
可使用如下 sql:
1 | select * from users where is_admin is null; |
PL/SQL Developer 配置
操作系统: Windows 10
安装 Instant Client
官网(Instant Client for Microsoft Windows (x64) 64-bit | Oracle 中国) 下载 instantclient-basic-windows.x64-21.6.0.0.0dbru.zip 这种即可,版本自选,下载完成后解压,添加到环境变量。
注意下载链接的 Description 最后一项:
The 21c Basic package requires the Microsoft Visual Studio 2017 Redistributable.
如果没有安装,则打开 Pl/SQL 时会出现类似如下的错误:
1 | 不能初始化 "..\oci.dll" |
按照 Description 中的链接下载安装。
语言设置:
在环境变量中加入:
1 | 变量名:NLS_LANG |
参考:
1、https://blog.csdn.net/stevendbaguo/article/details/54971914
2、https://wenku.baidu.com/view/2297e9bc3968011ca2009130.html
日期格式设置:
在环境变量中加入:
1 | 变量名:NLS_DATE_FORMAT |
参考:https://www.cnblogs.com/stono/p/5533492.html
环境变量->系统变量 -> 新建:
| 变量名 | 变量值 | |
|---|---|---|
| 时间 | NLS_DATE_FORMAT | YYYY-MM-DD HH24:MI:SS |
| NLS_TIMESTAMP_FORMAT | YYYY-MM-DD HH24:MI:SS | |
| 语言 | NLS_LANG | SIMPLIFIED CHINESE_CHINA.ZHS16GBK |
重新启动 PL/SQL。
Ubuntu iptables
Ubuntu 编写的 iptables 规则,在重启后会失效;使用 iptables-persistent 持久化保存。
1 | sudo apt install iptables-persistent |
编写完规则后,执行:
1 | sudo netfilter-persistent save |
参考 :
1、ubuntu/debian iptables规则持久化,iptables-persistent
2、 https://help.ubuntu.com/community/IptablesHowTo#Solution_.233_iptables-persistent
添加防火墙过滤规则步骤如下;
1、查看现有防火墙过滤规则:
iptables -nvL --line-number
2、添加防火墙过滤规则(设置白名单):
1)添加白名单
iptables -I INPUT 3 -s 136.6.231.163 -p tcp --dport 1521 -j ACCEPT
命令详解:
-I:添加规则的参数
INPUT:表示外部主机访问内部资源
3:表示添加到第三行(可以任意修改)
-s:指定作为源地址匹配,这里不能指定主机名称,必须是IP;
-p: 用于匹配协议的(这里的协议通常有3种,TCP/UDP/ICMP)
--dport: 用于匹配端口号
-j: 用于匹配处理方式:
常用的ACTION:
DROP:悄悄丢弃
一般我们多用DROP来隐藏我们的身份,以及隐藏我们的链表
REJECT:明示拒绝
ACCEPT:接受
2)查看添加结果
iptables -nvL --line-number
原文链接:https://blog.csdn.net/qq_37837701/java/article/details/80578807
https://blog.csdn.net/sanve/article/details/80881380
IP地址网段表示法](https://www.cnblogs.com/amyzhu/p/11396136.html)
172.12.34.0/25
- 子网掩码:用于表示IP地址中的多少位用来做主机号。因为”其中值为1的比特留给网络号和子网号,为0的比特留给主机号”(TCP/IP V1)。
- 172.12.34.0/25含义:
- 172.12.34.0——表示一个子网号
- 25——表示采用子网掩码中国呢的前25位为有效未,即用 32-25=7big 来表示主机号,该子网可以容纳 2^7-2=126台主机。
- 因此172.12.34.0/25 表示IP范围为 172.12.34.1~172.12.34.126
Ubuntu 安装 PHP 的 PDO_OCI 扩展
已经用 apt 安装了 php7.3-cli,php7.3-fpm,php7.3-dev 等。
安装了 Oracle 的 Instant Client(可参考:https://hefengbao.github.io/helloword/ubuntu-install-oracle-instant-client-and-oci-20180511/ ),现在安装 pdo_oci, 貌似只能通过源码安装:
下载 php 源码
wget https://www.php.net/distributions/php-7.3.16.tar.xz
1 | tar -xvf php-7.3.16.tar.xz |
phpize
1 | /usr/bin/phpize7.3 |
结果如下:
Configuring for:
PHP Api Version: 20180731
Zend Module Api No: 20180731
Zend Extension Api No: 320180731
1 | ./configure --with-pdo-oci=instantclient,/usr/lib/oracle/19.5/client64/lib --with-oci8=instantclient,/usr/lib/oracle/19.5/client64/lib -with-php-config=/usr/bin/php-config7.3 |
1 | sudo make |
结果如下:
Installing shared extensions: /usr/lib/php/20180731/
把 extension=pdo_oci 添加到 /etc/php/7.3/cli/php.ini、/etc/php/7.3/fpm/php.ini
php -m 查看。
参考:
https://www.fujieace.com/php/php-extensions/config-m4.html
https://blog.csdn.net/Zhang_Ying_Jie/article/details/79315022
https://blogs.oracle.com/opal/updated-php-72-pdo_oci-install-configure-syntax
Erroneous data format for unserializing 'Symfony Component Routing CompiledRoute'
运行 php artisan route:cache 出现如下错误:
1 | ErrorException |

运行其他一些命令也会出现如上错误,
删除 bootstap/cache/route.php 文件。
OkHttp Interceptor - Making the most of it
In this blog, we will learn how to work with the OkHttp Interceptors. We will also see the real use cases where we can use it and how we can use it to get the most of it. In Android, we have so many use-cases that can be done using the OkHttp Interceptors.
Today, we will cover the following sections to master it:
- What are Interceptors?
- Types of Interceptors.
- How to add Interceptors in OkHttpClient?
- Creating the Interceptor.
- Real use-cases using the Interceptors.
What are Interceptors?
According to documentation, Interceptors are a powerful mechanism that can monitor, rewrite, and retry the API call. So basically, when we do some API call, we can monitor the call or perform some tasks.
In simple words, Interceptors are like the security personnel in the security check process at the Airport. They check our boarding pass, put a stamp on it and then would allow us to pass.

We can use the interceptors to do so many things, for example, monitor the API calls centrally. Generally, we need to add the logger for each network call, but by using the interceptor, we can add one logger centrally and that will work for all the network calls. Another use-case can be caching the response of network calls to build the offline-first app, we will learn it later in this blog in detail.
Types of Interceptors
We have two types of interceptors as follows:
- Application Interceptors: These are interceptors that are added between the Application Code(our written code) and the OkHttp Core Library. These are the ones that we add using addInterceptor().
- Network Interceptors: These are interceptors that are added between the OkHttp Core Library and the Server. These can be added to OkHttpClient using addNetworkInterceptor().
How to add interceptors in OkHttpClient?
While building the OkHttpClient object, we can add the interceptor like below:
1 | fun myHttpClient(): OkHttpClient { |
Here, in addInterceptor we pass the interceptor that we have created. Now, let’s see how to create the Interceptor.
Creating the Interceptor
To create the interceptor, we need to create a class by implementing the Interceptor interface like below:
1 | class MyInterceptor : Interceptor { |
Here, in the intercept(), we can perform any action which we want inside it.
And to use the interceptor, we can use like below:
1 | fun myHttpClient(): OkHttpClient { |
We can add the MyInterceptor in addInterceptor().
Now, let’s discuss more real use-cases where we can use the Interceptors.
Real use-cases using the Interceptors
The following are the common use-cases in Android:
Logging the errors centrally
First, we need to create the ErrorInterceptor like below:
1 | class ErrorInterceptor : Interceptor { |
- First, we get the request from chain.request()
- Then, we get the response returned from the server, by passing the request in chain.proceed(request)
- Now, we can check for the response code and perform an action.
- We can pass the error to the view using via the interfaces or by using something like RxJava, EventBus, and etc.
- Let’s say if we get a 401 error i.e. Unauthorized then we can perform an action to clear the app data/log out the user or any action which we want to perform.
Now, to use this ErrorInterceptor in our OkHttpClient, we can add like below:
1 | .addInterceptor(ErrorInterceptor()) |
This is how we can create a centralized Error Logger using the Interceptor.
OkHttp has a built-in logger which is very useful for debugging.
To learn more about the built-in logger, click here.
Note: If we want to log the details for the redirection of URL, consider using the interceptor at the network layer using the addNetworkInterceptor().
Caching the response
If we want to cache the response of the API call so that if we call the API again, the response comes out from Cache.
Let’s say we have the API call from Client to Server and Cache-Control header is enabled from the server, then OkHttp Core will respect that header and cache the response for a certain time being which was sent from the server.
But what if the Cache-Control is not enabled from the server. We still can cache the response from OkHttp Client using Interceptor.

Just see the above image. Here, what we have to do is that we have to intercept the Response before going inside the OkHttp Core and add the header (Cache-Control), so it will be treated as if the response(with the Cache-Control header) has come from the server, and OkHttp Core will respect that and cache the response.
We will create an interceptor like below:
1 | class CacheInterceptor : Interceptor { |
Here, we have a CacheControl which is used to provide the header for Cache-Control.
Finally, we can add like below:
1 | .addNetworkInterceptor(CacheInterceptor()) |
Here, if we see, we are not using the addInterceptor() but using addNetworkInterceptor() for the use case. This is because in this case, the operation is happening at the network layer.
But, there is something important, we need to consider while building the offline-first app.
The cached response will be returned only when the Internet is available as OkHttp is designed like that.
- When the Internet is available and data is cached, it returns the data from the cache.
- Even when the data is cached and the Internet is not available, it returns with the error “no internet available“.
What to do now?
We can use the following ForceCacheInterceptor at the Application layer in addition to the above one (CacheInterceptor, only if not enabled from the server). To implement in the code, we will create a ForceCacheInterceptor like below:
1 | class ForceCacheInterceptor : Interceptor { |
We can add the Interceptor in OkHttpClient like below:
1 | .addNetworkInterceptor(CacheInterceptor()) // only if not enabled from the server |
Here, we are adding the ForceCacheInterceptor to OkHttpClient using addInterceptor() and not addNetworkInterceptor() as we want it to work on the Application layer.
Adding the Header like Access Token centrally
Let’s say that we have to make the API calls and we have to add Authorization Header in all the API calls. Either we can use it individually or we can centralize that using the Interceptor.
1 | class AuthTokenInterceptor : Interceptor { |
- First, we get the token for the header from our local storage like a SharedPreference.
- Here, we intercept the original request which we triggered from the application using chain.request() and set it to originalRequest.
- Then, we build the request again by adding the Header with the key and value which is required to make the network call.
- Then, we will build the request again and return the response using chain.proceed(request) by passing the new request which is having the Authorization header.
This is how we can centralize the Header which is common in all the API Calls. Now to use it in the OkHttpClient, we will do like below:
1 | .addInterceptor(AuthTokenInterceptor()) |
Let’s go to another use-case.
Refreshing the Access Token at Single Place
Let us say we have a use-case that when we get a 401 error in the Error Interceptor and we need to refresh the auth token as we have an Unauthorized error. We can do that using the below:
1 | override fun intercept(chain: Interceptor.Chain): Response { |
- If we get the response.code() as 401 i.e. Unauthorized, we will refresh the token here, then modify the request by adding the new header and make the new request to the server.
Note: Another way that is more flexible when it comes to refreshing the Access Token is to use the Authenticator interface of OkHttp.
Now, let’s move to another use-case.
Enabling Gzip at Android End
Gzip is used for data compression. In Android as well, we can use the Gzip for the compression using the interceptor.
So, while getting a response, OkHttp automatically respects the header (content encoding) and decompresses the data and returns, but let’s say when we have to send compressed data to a server, then we have to write our own interceptor.
We can find the GzipRequestInterceptor class here.
To use the interceptor we can use like below:
1 | .addInterceptor(GzipRequestInterceptor()) |
So, these are the real use-cases, how can we use the interceptors in our Android App. We can do a lot of things with interceptors. Let’s start making the most of it.
来源:
https://blog.mindorks.com/okhttp-interceptor-making-the-most-of-it