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

Koa2 프레임워크를 통해 CORS를 사용하여 도메인 간 Ajax 요청을 구현하는 방법

亚连
亚连원래의
2018-06-01 11:17:231572검색

이 기사에서는 CORS를 사용하여 도메인 간 Ajax 요청을 완료하는 Koa2 프레임워크를 주로 소개하고 참고용으로 제공합니다.

교차 도메인 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입니다. 요청에 성공적으로 응답할 수 있는지 여부입니다.

서버에서 이 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 요청에 응답할 수 있지만 이 도메인 아래의 쿠키는 요청 헤더에 전달되지 않습니다. 쿠키를 서버로 가져오고 서버가 쿠키를 추가로 설정하도록 허용하려면 추가 구성이 필요합니다.

후속 감지를 용이하게 하기 위해 도메인 이름 http://127.0.0.1:3001에 두 개의 쿠키를 미리 설정합니다. 실수로 쿠키를 중국어로 설정하지 않도록 주의하세요. (그냥 중국어로 설정했는데 결과가 에러가 나더군요. 오랫동안 에러의 원인을 찾지 못했습니다.)

그러면 2단계를 해야 합니다. 첫 번째 단계는 응답 헤더 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();
});

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

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

webpack打包js的方法

vue 简单自动补全的输入框的示例

angular5 httpclient的示例实战

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

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