Talking about how the Koa2 framework uses CORS to complete cross-origin ajax requests.

Source: Internet
Author: User

Talking about how the Koa2 framework uses CORS to complete cross-origin ajax requests.

There are many ways to implement cross-origin ajax requests. One of them is to use CORS, and the key to this method is to configure it on the server side.

This article only describes the basic configurations that can complete normal cross-origin ajax response (I will not perform in-depth configuration ).

CORS divides requests into simple requests and non-simple requests. It can be simply considered that a simple request is a get and post request without an additional request header, and if it is a post request, the request format cannot be application/json (because I do not have a deep understanding of this part. If an error occurs, I hope someone can point it out and propose a change ). The rest are put, post, Content-Type application/json, and custom request headers.

The configuration of a simple request is very simple. To achieve the goal, you only need to configure Access-Control-Allow-Origin in the response header.

If you want to access the http: // 127.0.0.1: 3000 domain name under the http: // localhost: 3001 domain name. You can make the following configurations:

app.use(async (ctx, next) => { ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000'); await next();});

Then, you can use ajax to initiate a simple request, such as a post request, to easily obtain the correct response from the server.

The experiment code is as follows:

$.ajax({  type: 'post',  url: 'http://127.0.0.1:3001/async-post' }).done(data => {  console.log(data);})

Server code:

router.post('/async-post',async ctx => { ctx.body = { code: "1", msg: "succ" }});

Then you can get the correct response information.

At this time, if you look at the request and response header information, you will find that the request header has an origin (and a referer is the url address of the request ), an Access-Control-Allow-Origin is added to the response header.

Now you can send simple requests, but other configurations are required to send non-simple requests.

When a non-simple request is sent for the first time, two requests are actually sent. The preflight request is sent for the first time. The request method of this request is OPTIONS, whether the request passes determines whether non-simple requests of this type can be responded successfully.

In order to be able to match the OPTIONS type request on the server, you need to make a middleware for matching and provide a response so that the pre-check can pass.

app.use(async (ctx, next) => { if (ctx.method === 'OPTIONS') { ctx.body = ''; } await next();});

In this way, the OPTIONS request will pass.

If you check the request header of the preflight request, you will find two more request headers.

Access-Control-Request-Method: PUTOrigin: http://localhost:3000

You need to negotiate with the server through the two headers to check whether the server response conditions are met.

It is easy to understand that since the request header has two more information, the response header should naturally have two information counterparts. The two information is as follows:

Access-Control-Allow-Origin: http://localhost:3000Access-Control-Allow-Methods: PUT,DELETE,POST,GET

The first message is the same as the origin, so it passes. The second message corresponds to Access-Controll-Request-Method. If the Request Method is included in the response Method permitted by the server, the Request passes. Both constraints are met, so the request can be initiated successfully.

So far, only the pre-check has been completed and no real request has been sent.

Of course, the real request also succeeded in obtaining a response, and the response header is as follows (not important)

Access-Control-Allow-Origin: http://localhost:3000Access-Control-Allow-Methods: PUT,DELETE,POST,GET

The request header is as follows:

Origin: http://localhost:3000

This is obvious. The response header information is set on the server, so this is the case.

The client does not need to send the Access-Control-Request-Method Request Header because it has already been pre-checked.

The code for this example is as follows:

$.ajax({   type: 'put',   url: 'http://127.0.0.1:3001/put'  }).done(data => {   console.log(data);});

Server code:

app.use(async (ctx, next) => {  ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000');  ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');  await next();});

At this point, we have completed the basic configuration for correct cross-origin ajax response and some further configuration items.

For example, so far, every non-simple request actually sends two requests and one real request for pre-check, which results in a loss of performance. In order not to send a pre-check request, you can configure the following response header.

Access-Control-Max-Age: 86400

The purpose of this response header is to set a relative time starting from the moment the non-simple request passes the verification on the server side, when the number of milliseconds that have elapsed is less than Access-Control-Max-Age, you do not need to perform a pre-check. You can directly send a request.

Of course, there is no pre-check for a simple request, so this code does not make sense for a simple request.

The current Code is as follows:

app.use(async (ctx, next) => { ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000'); ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET'); ctx.set('Access-Control-Max-Age', 3600 * 24); await next();});

So far, cross-origin ajax requests can be responded, but cookies in this domain are not carried in the request header. If you want to bring the cookie to the server and allow the server to further set the cookie, further configuration is required.

To facilitate subsequent detection, we set two cookies under the http: // 127.0.0.1: 3001 domain name. Do not set the cookie to Chinese by mistake (I set it to Chinese just now, and an error is returned. The error cause is not found for half a day)

Next, let's take two steps. The first step is to set the Response Header Access-Control-Allow-Credentials to true, and then set the xhr object's withCredentials attribute to true on the client side.

The client code is as follows:

$. Ajax ({type: 'put', url: 'http: // 127.0.0.1: 3001/put', data: {name: 'huang tianhao', age: 20}, xhrFields: {withCredentials: true }}). done (data => {console. log (data );});

The server is as follows:

app.use(async (ctx, next) => {  ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000');  ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');  ctx.set('Access-Control-Allow-Credentials', true);  await next();});

Then you can bring the cookie to the server, and the server can also modify the cookie. However, the cookie is still a cookie under the http: // 127.0.0.1: 3001 domain name. No matter how the operation is performed, the cookie under the domain name cannot be accessed.

So far, the basic functions of CORS have been mentioned.

At first, I did not know how to give Access-Control-Allow-Origin. Later I was reminded that I could write a white list array, then, when receiving the request, determine whether the origin is in the White List array and dynamically set Access-Control-Allow-Origin. The Code is as follows:

app.use(async (ctx, next) => { if (ctx.request.header.origin !== ctx.origin && whiteList.includes(ctx.request.header.origin)) {  ctx.set('Access-Control-Allow-Origin', ctx.request.header.origin);  ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');  ctx.set('Access-Control-Allow-Credentials', true);  ctx.set('Access-Control-Max-Age', 3600 * 24); } await next();});

In this way, you can match multiple origins without wildcard characters.

Note: ctx. origin and ctx. request. header. different Origins, ctx. origin is the domain name of the server, ctx. request. header. the origin is the origin of the request header. Do not confuse the two.

Finally, we will slightly adjust the structure of the custom middleware to prevent Access-Control-Allow-Methods and Access-Control-Max-Age from being returned for each request, these two response headers do not need to be returned every time, but they can be returned when there is a pre-check for the first time.

The adjusted sequence is as follows:

app.use(async (ctx, next) => { if (ctx.request.header.origin !== ctx.origin && whiteList.includes(ctx.request.header.origin)) {  ctx.set('Access-Control-Allow-Origin', ctx.request.header.origin);  ctx.set('Access-Control-Allow-Credentials', true); } await next();});app.use(async (ctx, next) => { if (ctx.method === 'OPTIONS') {  ctx.set('Access-Control-Allow-Methods', 'PUT,DELETE,POST,GET');  ctx.set('Access-Control-Max-Age', 3600 * 24);  ctx.body = ''; } await next();});

In this way, redundant response headers are reduced.

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.