คำแนะนำฉบับสมบูรณ์เกี่ยวกับการตั้งค่าพร็อกซีใน Angular สำหรับการเรียก API หลังพร็อกซีขององค์กรหรือด้วยการรับรองความถูกต้องของ Windows

นักพัฒนาเชิงมุมใช้ Angular CLI เพื่อการพัฒนาท้องถิ่น ความต้องการที่พบบ่อยที่สุดประการหนึ่งคือการตั้งค่าพร็อกซีในสภาพแวดล้อม dev ภายในเครื่องเพื่อหลีกเลี่ยงข้อผิดพลาด CORS เมื่อแอป Angular ส่งคำขอ HTTP ไปยัง API ที่อยู่ในโดเมนอื่น Angular CLI ทำให้กระบวนการค่อนข้างง่าย แต่อาจยุ่งยากในบางกรณี

ในบทความนี้ ฉันจะพูดถึงวิธีตั้งค่าพร็อกซีเซิร์ฟเวอร์ dev

ตั้งค่าพร็อกซีเพื่อเชื่อมต่อกับ API ใน localhost

ด้วย Angular CLI เราสามารถเริ่มเซิร์ฟเวอร์ dev ภายในเครื่องได้โดยใช้คำสั่งด้านล่าง

ng serve

คำสั่งเรียกใช้เซิร์ฟเวอร์ dev ภายในตาม "เซิร์ฟเวอร์ webpack dev" ตามค่าเริ่มต้น เซิร์ฟเวอร์ dev จะทำงานบน http://localhost:4200

เมื่อแอป Angular ต้องการเรียก API แบ็กเอนด์ซึ่งโฮสต์อยู่ในเครื่องที่ http://localhost:3000, เราจะพบข้อผิดพลาด CORS เนื่องจากการเรียก HTTP ใช้ต้นทางอื่น (localhost:3000)

this.http.get('http://locahost:3000/api/')
    .subscribe(res => {...});

ปัญหา CORS สามารถแก้ไขได้ด้วยการกำหนดค่าพร็อกซีเซิร์ฟเวอร์ Angular dev คุณสามารถสร้างการกำหนดค่าพร็อกซีตัวอย่างได้ที่ด้านล่าง

// proxy.conf.json
{
  "/api": {
    "target": "http://localhost:3000",
    "secure": false,
  }
}
// we change the angular http call to remove the domain prefix
this.http.get('/api/')
    .subscribe(res => {...});

ดังที่แสดงในแผนภาพต่อไปนี้ พร็อกซีจะอยู่ระหว่างแอป Angular และ API แบ็กเอนด์ และแปลการเรียก “api/v1” เป็น API แบ็กเอนด์ ข้อผิดพลาด CORS จะไม่เกิดขึ้นเนื่องจากการเรียกไปยัง API มีต้นกำเนิดเดียวกัน (localhost:4200/api) ในขณะนี้

เพื่อให้การกำหนดค่าพร็อกซีมีผล จะต้องส่งผ่านไปยังคำสั่ง ng serve

ng serve --proxy-config proxy.conf.json

หรือเราสามารถเพิ่มลงในการกำหนดค่า angular.json ได้

"serve": {
  ...
  "options": {
    ...
    "proxyConfig": "proxy.conf.json"
  }
}

เชื่อมต่อกับ API ภายนอกที่อยู่ด้านหลังพร็อกซีขององค์กร

บ่อยครั้งที่เราทำงานภายในเครือข่ายองค์กร และแอป Angular ในสภาพแวดล้อมการพัฒนาท้องถิ่นยังจำเป็นต้องเชื่อมต่อกับ API ภายนอกด้วย จากตัวอย่างก่อนหน้านี้ เราอาจจำเป็นต้องเรียก "http://abc.company.com/api" ในแอป Angular แทนที่จะเรียก "http://localhost:3000/api"

การเข้าถึง API ภายนอกหลังพร็อกซีของบริษัทจำเป็นต้องกำหนดค่าตัวแปรสภาพแวดล้อม HTTP_PROXY และ HTTPS_PROXY หากพร็อกซีใช้ใบรับรอง SSL จะต้องตั้งค่าสถานะ secure เป็นเท็จ เพื่อข้ามการตรวจสอบใบรับรอง

ในการจัดการพร็อกซีขององค์กร เราต้องสร้าง proxy.conf.js ตามด้านล่างนี้

const HttpsProxyAgent = require('https-proxy-agent');

const proxyConfig = [
  {
    context: '/api',
    pathRewrite: { '^/api': '' },
    target: 'https://api.abc.com',
    changeOrigin: true,
    secure: false
  }
];

function setupForCorporateProxy(proxyConfig) {
  const proxyServer = process.env.http_proxy || process.env.HTTP_PROXY;

  if (proxyServer) {
    const agent = new HttpsProxyAgent(proxyServer);
    proxyConfig.forEach(c => {
      c.agent = agent;
    });
  }
  return proxyConfig;
}

module.exports = setupForCorporateProxy(proxyConfig);

ในตัวอย่างข้างต้น เราพร็อกซีคำขอ เช่น api/v1/client ไปยังเซิร์ฟเวอร์ภายนอก https://api.abc.com/v1/client เมื่อจำเป็นต้องใช้พร็อกซีขององค์กร เราจะตั้งค่าออบเจ็กต์ HTTPS agent ในพร็อกซีตามตัวแปรสภาพแวดล้อม HTTP_PROXY และ HTTPS_PROXY เพิ่มตัวเลือก secure:false เพื่อจัดการใบรับรอง SSL แบบกำหนดเองในพร็อกซีขององค์กร

หากต้องการใช้การกำหนดค่า js ใหม่สำหรับแอป Angular ให้รันสิ่งต่อไปนี้

ng serve --proxy-config proxy.conf.js

เป็นที่น่าสังเกตว่ามีเอเจนต์สองประเภท: HttpsProxyAgent และ HttpProxyAgent, จำเป็นต้องเลือกเอเจนต์ที่เหมาะสมตามการตั้งค่าสภาพแวดล้อม

พร็อกซีเป็น API โดยใช้การรับรองความถูกต้องของ windows (IIS)

การรับรองความถูกต้องของ Windows ถูกใช้กันอย่างแพร่หลายในหลายๆ บริษัทที่พึ่งพาระบบนิเวศของ Microsoft สถานการณ์อาจเป็นเรื่องยุ่งยากหากแอป Angular เชื่อมต่อกับบริการ API ที่โฮสต์ด้วย IIS ซึ่งได้รับการป้องกันโดยการรับรองความถูกต้องของ Windows

ปัญหาทั่วไปคือการโทรจากแอป Angular ไปยัง API จะส่งกลับ 401 เมื่อใช้การตั้งค่าพร็อกซีในสภาพแวดล้อมการพัฒนาท้องถิ่น

ตัวอย่างเช่น /api/v1/../login เป็นจุดสิ้นสุดที่ได้รับการปกป้องโดย Windows Authentication คำขอไปยัง API จาก Angular App ที่รันในเครื่องจะได้รับการตอบกลับที่ไม่ได้รับอนุญาต 401 รายการ ด้านล่างนี้คือภาพหน้าจอแท็บเครือข่ายในเครื่องมือนักพัฒนา Chrome

สาเหตุหลักของปัญหาคือการรับรองความถูกต้องของ Windows นั้นขึ้นอยู่กับการเชื่อมต่อ แต่พรอกซีตัดการเชื่อมต่อแบบ Keep-Live

ภายใต้ประทุนของการรับรองความถูกต้องของ windows จะใช้ Kerberos หรือ NTLM โปรโตคอลใดโปรโตคอลหนึ่งจะต้องมีการเชื่อมต่อแบบ Keep-Live เพื่อรักษาสถานะการรับรองความถูกต้อง

เมื่อเรียก /api/v1/../login เบราว์เซอร์จะพยายามสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ IIS ผ่านการจับมือเจรจา NTLM ซึ่งประกอบด้วย 3 ส่วน ได้แก่ข้อความ Type-1, Type-2 และข้อความ Type-3 ดูรายละเอียดเพิ่มเติมเกี่ยวกับการจับมือ NTLM ได้ "ที่นี่" คุณอาจสังเกตเห็นแล้วว่ามีการเรียก HTTP สองครั้งที่แสดงสำหรับคำขอเดียวกันในภาพหน้าจอด้านบน มันคือสองส่วนแรกของการจับมือกัน

เนื่องจากคำขอเป็นแบบพร็อกซีในเครื่อง ข้อความจับมือ 3 รายการจึงถูกส่งไปในคำขอ (ซ็อกเก็ต) 3 รายการแยกกันผ่านพร็อกซี ดังนั้นจึงไม่สามารถรักษาการเชื่อมต่อแบบ Keep-Live ไว้ในกระบวนการได้ นั่นคือสาเหตุที่ข้อความสุดท้ายไม่เกิดขึ้น

เพื่อแก้ไขปัญหา เราจำเป็นต้องกำหนดค่าพร็อกซีเพื่อรักษาการเชื่อมต่อเดียวระหว่างเบราว์เซอร์และเซิร์ฟเวอร์ IIS แพ็คเกจagentkeepaliveสามารถช่วยให้เราบรรลุเป้าหมายนี้ได้ การกำหนดค่าพร็อกซีที่อัปเดตแสดงอยู่ด้านล่าง

const Agent = require("agentkeepalive");

const keepaliveAgent = new Agent({
    maxSockets: 1,
    keepAlive: true,
    maxFreeSockets: 10,
    keepAliveMsecs: 1000,
    timeout: 60000,
    keepAliveTimeout: 30000 // free socket keepalive for 30 seconds
});

const PROXY_CONFIG = [
    {
        target: "http://localhost:3000",
        context: "/api",
        secure: false,
        changeOrigin: true,
        loglevel: "debug",
        agent: keepaliveAgent
    }
];
module.exports = PROXY_CONFIG;

การกำหนดค่าพร็อกซีที่อัปเดตจะตั้งค่าสถานะ maxSockets เป็น 1, keepAlive เป็นจริง และตั้งค่าการหมดเวลาเป็น 30 วินาที ซึ่งนานพอที่จะทำให้การจับมือเสร็จสมบูรณ์ การกำหนดค่านี้มีจุดมุ่งหมายเพื่อให้ http.Agent รักษาการเชื่อมต่อแบบต่อเนื่องระหว่างเบราว์เซอร์และเซิร์ฟเวอร์ IIS ผ่านทางพร็อกซีในกระบวนการตรวจสอบสิทธิ์

ตอนนี้คำขอ /api/v1/../login API ควรใช้งานได้

ด้านบนคือบันทึกแท็บเครือข่ายหลังจากการตรวจสอบความถูกต้องด้วยการกำหนดค่าใหม่สำเร็จ เราจะเห็นคำขอทั้งสามในระหว่างการแฮนด์เชค และคำขอสุดท้ายส่งคืนสถานะความสำเร็จของ HTTP 200

หลายรูปแบบในส่วนหัว WWW-Authenticate เดียว

สาเหตุที่เป็นไปได้อีกประการหนึ่งของข้อผิดพลาดจากการรับรองความถูกต้องของ Windows คือส่วนหัว www-authenticate ตาม RFC 7235 การมีรูปแบบการรับรองความถูกต้องหลายรูปแบบในฟิลด์ส่วนหัว www-authenticate เดียวเป็นเรื่องปกติ แม้ว่าจะทำให้แยกวิเคราะห์ฟิลด์ได้ยากก็ตาม

เจ้าหน้าที่จะต้องใช้ความระมัดระวังเป็นพิเศษในการแยกวิเคราะห์ค่าฟิลด์ส่วนหัว WWW-
Authenticate หรือ Proxy-Authenticate หากมี
มากกว่าหนึ่งความท้าทาย หรือหากมีฟิลด์ WWW-Authenticate header
มากกว่าหนึ่งรายการ มีให้ เนื่องจากเนื้อหาของการท้าทายอาจมี
มีรายการพารามิเตอร์การตรวจสอบสิทธิ์ที่คั่นด้วยเครื่องหมายจุลภาค

ความจริงก็คือการรองรับเบราว์เซอร์นั้น น่าสงสัย ด้านล่างนี้เป็นตัวอย่างของส่วนหัว www-authenticate ที่มี 2 รูปแบบ

WWW-Authenticate: Negotiate, NTLM

เบราว์เซอร์บางตัวอาจไม่สามารถแยกวิเคราะห์ข้างต้นได้อย่างถูกต้อง และจะทำให้กระบวนการจับมือ NTLM หยุดทำงาน เพื่อแก้ไขปัญหานี้ เราสามารถใช้การโทรกลับ proxyRes ใน http-proxy-middleware ดังต่อไปนี้

const onProxyRes = function (proxyRes, req, res) {
     var key = 'www-authenticate';
     proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
};

// add it into the proxy config option
onProxyRes: onProxyRes

การกำหนดค่าพร็อกซีแบบเต็มมีลักษณะดังนี้

const Agent = require("agentkeepalive");

const keepaliveAgent = new Agent({
    maxSockets: 1,
    keepAlive: true,
    maxFreeSockets: 10,
    keepAliveMsecs: 1000,
    timeout: 60000,
    keepAliveTimeout: 30000 // free socket keepalive for 30 seconds
});
const onProxyRes = function (proxyRes, req, res) {
     var key = 'www-authenticate';
     proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
};
const PROXY_CONFIG = [
    {
        target: "http://localhost:3000",
        context: "/api",
        secure: false,
        changeOrigin: true,
        onProxyRes: onProxyRes,
        agent: keepaliveAgent
    }
];
module.exports = PROXY_CONFIG;

ด้วยการเพิ่มการโทรกลับใหม่ รูปแบบต่างๆ ในส่วนหัว www-authenticate จะถูกส่งไปหลายบรรทัด และการจับมือเจรจา NTLM จะสามารถดำเนินการต่อได้

// From the original response header
www-authenticate: Negotiate, NTLM

// After the onProxRes callback function
www-authenticate: ['Negotiate', 'NTLM']

// It is equivalent to
< WWW-Authenticate: Negotiate
< WWW-Authenticate: NTLM

สรุป

ในบทความนี้ เราจะพูดถึงวิธีหลีกเลี่ยงปัญหา CORS ด้วยการตั้งค่าพร็อกซีโดยใช้ Angular CLI เพื่อการพัฒนาในเครื่อง ฉันหวังว่ามันจะมีประโยชน์สำหรับคุณ หากคุณกำลังใช้งาน Angular ด้านหลังพร็อกซีขององค์กร และ/หรือใช้ IIS พร้อมการรับรองความถูกต้องของ Windows

ขอให้มีความสุขในการเขียนโปรแกรม!

เนื้อหาเพิ่มเติมได้ที่ PlainEnglish.io.

ลงทะเบียนเพื่อรับ จดหมายข่าวรายสัปดาห์ฟรี ของเรา ติดตามเราบน Twitter, LinkedIn, YouTube และ Discord .

สนใจที่จะขยายขนาดการเริ่มต้นซอฟต์แวร์ของคุณหรือไม่ ลองดูที่ วงจร