>  기사  >  웹 프론트엔드  >  Koa2 프레임워크의 CORS를 사용하여 도메인 간 Ajax 요청을 완료하는 방법

Koa2 프레임워크의 CORS를 사용하여 도메인 간 Ajax 요청을 완료하는 방법

php中世界最好的语言
php中世界最好的语言원래의
2018-03-28 11:50:571848검색

이번에는 Koa2 프레임워크의 CORS를 사용하여 Cross-domain Ajax 요청을 완료하는 방법을 보여드리겠습니다. Koa2 프레임워크의 CORS를 사용하여 Cross-domain Ajax 요청을 완료할 때 주의해야 할 주의사항은 무엇인가요? 다음은 실제 사례입니다. 살펴보겠습니다.

교차 도메인 Ajax 요청을 구현하는 방법에는 여러 가지가 있으며 그 중 하나는 CORS를 사용하는 것이며 이 방법의 핵심은 서버 측에서 구성하는 것입니다.

이 글에서는 일반적인 크로스 도메인 Ajax 응답을 완료할 수 있는 가장 기본적인 구성만 설명합니다. (자세한 구성은 어떻게 해야할지 모르겠습니다.)

CORS는 요청을 단순 요청과 비단순 요청으로 구분합니다. 추가 요청 헤더 없이 단순 요청은 get 및 post 요청이라고 간단히 생각할 수 있으며, post 요청인 경우 요청 형식은 application/json이 될 수 없습니다. (저는 이 부분에 대한 깊은 이해가 없기 때문에. 만약 실수가 있다면 누군가가 실수를 지적하고 수정을 제안해줬으면 좋겠습니다.) 나머지 요청, Put 및 Post 요청, Content-Type application/json을 사용한 요청, 사용자 정의 요청 헤더가 있는 요청은 단순하지 않은 요청입니다.

단순 요청의 구성은 매우 간단합니다. 목표를 달성하기 위해 응답만 완료하면 되는 경우 응답 헤더에 Access-Control-Allow-Origin만 구성하면 됩니다.

http://localhost:3000 도메인 이름 아래의 http://127.0.0.1:3001 도메인 이름에 액세스하려는 경우. 다음과 같이 구성할 수 있습니다.

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

그런 다음 ajax를 사용하여 게시 요청과 같은 간단한 요청을 시작하면 서버에서 올바른 응답을 쉽게 얻을 수 있습니다.

실험 코드는 다음과 같습니다.

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

서버측 코드:

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

그러면 올바른 응답 정보를 얻을 수 있습니다.

이때 요청과 응답의 헤더 정보를 보면 요청 헤더에 추가적인 출처가 있고(요청의 URL 주소에 대한 리퍼러도 있음) 응답 헤더에는 추가 액세스 제어-허용-원점.

이제 간단한 요청을 보낼 수 있지만 단순하지 않은 요청을 보내려면 여전히 다른 구성이 필요합니다.

비단순 요청이 처음으로 발행되면 두 개의 요청이 발행됩니다. 첫 번째 요청은 이 요청의 요청 방법에 따라 이 요청의 통과 여부가 결정됩니다. 단순하지 않은 요청에 성공적으로 응답할 수 있는지 여부입니다.

서버에서 이 OPTIONS 유형 요청을 일치시키려면 이에 맞는 미들웨어를 만들고 사전 검사를 통과할 수 있도록 응답해야 합니다.

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

이렇게 하면 OPTIONS 요청이 전달될 수 있습니다.

실행 전 요청의 요청 헤더를 확인하면 요청 헤더가 두 개 더 있다는 것을 알 수 있습니다.

Access-Control-Request-Method: PUT
Origin: http://localhost:3000

이 두 헤더 정보를 통해 서버와 협상하여 서버 응답 조건을 충족하는지 확인하세요.

이해하기 쉽습니다. 요청 헤더에는 두 가지 정보가 더 있으므로 응답 헤더에는 당연히 해당하는 두 가지 정보가 있어야 합니다.

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

첫 번째 정보는 동일합니다. 원산지이므로 통과합니다. 두 번째 정보는 Access-Controll-Request-Method에 해당합니다. 서버에서 허용하는 응답 방법에 요청 방법이 포함되어 있으면 이 정보도 통과됩니다. 두 제약 조건이 모두 충족되므로 요청이 성공적으로 시작될 수 있습니다.

지금까지는 사전 확인만 완료하고 실제 요청을 보내지 않은 것과 같습니다.

물론 실제 요청도 응답을 성공적으로 받았고, 응답 헤더는 다음과 같습니다(중요하지 않은 부분 생략)

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

요청 헤더는 다음과 같습니다.

Origin: http://localhost:3000

이것은 매우 명백합니다. 응답 헤더 정보는 다음과 같이 설정됩니다. 우리는 서버에 있습니다. 그렇습니다.

클라이언트는 Access-Control-Request-Method 요청 헤더가 지금 미리 확인되었기 때문에 보낼 필요가 없습니다.

이 예제의 코드는 다음과 같습니다.

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

서버 코드:

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();
});

이제 Cross-domain Ajax 응답을 올바르게 수행하기 위한 기본 구성이 완료되었으며, 추가로 구성할 수 있는 몇 가지 사항이 있습니다.

예를 들어, 지금까지 모든 단순하지 않은 요청은 실제로 실행 전 요청과 실제 요청이라는 두 개의 요청을 발행하므로 성능이 저하됩니다. 실행 전 요청을 보내지 않으려면 다음 응답 헤더를 구성할 수 있습니다.

Access-Control-Max-Age: 86400

这个响应头的意义在于,设置一个相对时间,在该非简单请求在服务器端通过检验的那一刻起,当流逝的时间的毫秒数不足Access-Control-Max-Age时,就不需要再进行预检,可以直接发送一次请求。

当然,简单请求时没有预检的,因此这条代码对简单请求没有意义。

目前代码如下:

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();
});

到现在为止,可以对跨域ajax请求进行响应了,但是该域下的cookie不会被携带在请求头中。如果想要带着cookie到服务器,并且允许服务器对cookie进一步设置,还需要进行进一步的配置。

为了便于后续的检测,我们预先在http://127.0.0.1:3001这个域名下设置两个cookie。注意不要错误把cookie设置成中文(刚才我就设置成了中文,结果报错,半天没找到出错原因)

然后我们要做两步,第一步设置响应头Access-Control-Allow-Credentials为true,然后在客户端设置xhr对象的withCredentials属性为true。

客户端代码如下:

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

服务端如下:

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();
});

这时就可以带着cookie到服务器了,并且服务器也可以对cookie进行改动。但是cookie仍是http://127.0.0.1:3001域名下的cookie,无论怎么操作都在该域名下,无法访问其他域名下的cookie。

现在为止CORS的基本功能已经都提到过了。

一开始我不知道怎么给Access-Control-Allow-Origin,后来经人提醒,发现可以写一个白名单数组,然后每次接到请求时判断origin是否在白名单数组中,然后动态的设置Access-Control-Allow-Origin,代码如下:

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();
});

这样就可以不用*通配符也可匹配多个origin了。

注意:ctx.origin与ctx.request.header.origin不同,ctx.origin是本服务器的域名,ctx.request.header.origin是发送请求的请求头部的origin,二者不要混淆。

最后,我们再稍微调整一下自定义的中间件的结构,防止每次请求都返回Access-Control-Allow-Methods以及Access-Control-Max-Age,这两个响应头其实是没有必要每次都返回的,只是第一次有预检的时候返回就可以了。

调整后顺序如下:

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();
});

这样就减少了多余的响应头。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

在Vue2.0中http请求以及loading的展示

process和child_process使用详解

위 내용은 Koa2 프레임워크의 CORS를 사용하여 도메인 간 Ajax 요청을 완료하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.