本稿では、前回の記事で静的サイトをクラウドサーバーにデプロイする方法を紹介しましたが、今回はより実践的なウェブサイト構築に焦点を当てます。具体的には、バックエンドサービスとの連携を実現し、ドメインをバインドしてユーザーがアクセスできるようにする方法を解説します。
ソースコード:https://github.com/baburwang/web-deploy-demo-2.git
プロジェクトの準備
デモンストレーションのため、バックエンドサービスとフロントエンドアプリケーションの2つのプロジェクトを準備します。
バックエンドプロジェクト
まず、バックエンドプロジェクトを作成し、ウェブサイトのバックエンドサービスとして機能させます。このサービスはフロントエンドからのリクエストを受け取り、処理します。
mkdir backend-service
cd backend-service
npm init -y
npm install express
vim server.js
server.jsファイルの内容はシンプルで、Expressフレームワークを使用してWebサービスを起動し、/authエンドポイントでHTTPリクエストを処理します。
const express = require('express');
const app = express();
app.use(express.json());
app.post('/auth', (req, res) => {
const { username = '', password = '' } = req.body;
if (username !== 'user123') {
res.send({
status: {
code: 1,
message: `${username} は存在しません`
}
});
return;
}
if (password !== 'password123') {
res.send({
status: {
code: 2,
message: `パスワードが間違っています`
}
});
return;
}
res.send({
status: {
code: 0,
message: '',
},
result: {
id: 101,
username: 'user123',
}
});
});
app.listen(8081, () => {
console.log('バックエンドサービスが http://localhost:8081 で実行中');
});
nohup node server.js &
バックエンドプロジェクトファイルをクラウドサーバーにアップロードし、サービスを起動します。その後、Postmanなどのツールを使用してインターフェースをテストし、正常に動作することを確認します。
フロントエンドプロジェクト
次にフロントエンドプロジェクトを準備します。フロントエンドプロジェクトを初期化した後、ユーザーログインコンポーネントを作成します。
npm create vue@latest
<template>
<div class="login-container">
<div class="login-header">
<h1>ログイン</h1>
</div>
<div class="login-body">
<form @submit.prevent="handleLogin">
<div class="form-group">
<input v-model="credentials.username" type="text" placeholder="ユーザー名を入力" name="username" required>
</div>
<div class="form-group">
<input v-model="credentials.password" type="password" placeholder="パスワードを入力" name="password" required>
</div>
</form>
</div>
<div class="login-footer">
<button @click="handleLogin">ログイン</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const credentials = ref({
username: '',
password: ''
});
const handleLogin = () => {
console.log('ユーザー名:', credentials.value.username);
console.log('パスワード:', credentials.value.password);
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://203.0.113.45:8081/auth', true);
xhr.responseType = 'json';
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('応答:', xhr.response);
} else {
console.error('リクエストが失敗しました。ステータス:', xhr.status);
}
};
xhr.onerror = function() {
console.error('ネットワークエラー');
};
xhr.send(JSON.stringify({
username: credentials.value.username,
password: credentials.value.password,
}));
};
</script>
<style scoped>
.login-container {
text-align: center;
width: 320px;
height: 320px;
border-radius: 12px;
box-shadow: 0 0.5vw 1.5vw 0.4vw rgba(0,0,0,0.05), 0 0.33vw 0.83vw rgba(0,0,0,0.08), 0 0.17vw 0.33vw -0.21vw rgba(0,0,0,0.12);
padding: 25px 0;
.login-header {
h1 {
color: #2a2a2a !important;
font-size: 1.5vw;
font-weight: 500;
line-height: 2vw;
text-align: center;
}
}
.login-body {
margin: 25px 25px;
input {
height: 52px;
width: 100%;
background-color: #f0f0f0;
border: 1px solid transparent;
border-radius: 12px;
padding: 0 22px;
}
.form-group + .form-group {
margin-top: 12px;
}
}
.login-footer {
button {
font-size: 1.1vw;
font-weight: 500;
height: 2.8vw;
margin: 0 auto;
width: 15vw;
box-shadow: none;
border-radius: 0.65vw;
padding-left: 1.1vw;
padding-right: 1.1vw;
text-shadow: none;
background: #2a2a2a;
border-color: #2a2a2a;
color: #fff;
border: 1px solid #e0e0e0;
}
}
}
</style>
開発環境
まずローカル開発環境でログイン機能をテストします。ログインボタンをクリックすると、ブラウザコンソールに「Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.」というエラーが表示されます。これは明らかなクロスオリジン問題です。フロントエンドプロジェクトのアドレスはhttp://localhost:5173ですが、インターフェースリクエストアドレスはhttp://203.0.113.45:8081であり、ドメインとポートが異なるため、ブラウザの同一オリジンポリシー制限がトリガーされています。
重要な点は、クロスオリジンはブラウザの動作であり、サーバー側が正常に応答を返したとしても、ブラウザはセキュリティ上の理由からウェブページがその結果を読み取るのを阻止します。
開発プロセス中にインターフェースアクセスのクロスオリジン問題を解決するために、通常は開発サーバー(devServer)のプロキシ機能を利用します。devServerを構成することで、フロントエンドリクエストをバックエンドサーバーにプロキシし、ブラウザの同一オリジンポリシー制限を回避できます。これにより、開発段階でバックエンドインターフェースに正常にアクセスし、デバッグを行うことができます。
- まず、フロントエンドコード内のXHRリクエストアドレスを変更します。バックエンドサーバーのアドレス
http://203.0.113.45:8081/authに直接アクセスするのではなく、/api/authに置き換える必要があります。これにより、devServerによってインターセプトされるようになります。
const handleLogin = () => {
...
xhr.open('POST', '/api/auth', true);
...
};
- devServer設定で
/apiで始まるURLリクエストをプロキシします:
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
proxy: {
'/api': {
target: 'http://203.0.113.45:8081',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
}
}
}
})
なぜdevServerを使用するとクロスオリジン問題が解決されるのか、簡単に説明します。
-
ログインボタンをクリックすると、ブラウザはリクエストを送信します。この時のリクエストアドレスは
http://localhost:5173/api/authです。このリクエストアドレスのプロトコル、IP、およびポートはウェブページと一致しているため、ブラウザはクロスオリジンがないと判断します。 -
http://localhost:5173はdevServerプロセスであるため、devServerは自分自身へのインターフェースリクエストを監視し、かつそのURLが/apiで始まる場合、devServerは実際のバックエンドサーバーにリクエストを送信し、その応答結果をフロントエンドに返します。
この方法により、開発環境でのクロスオリジンリクエスト問題を解決しました。
本番環境
本番環境でのクロスオリジンリクエスト処理は、開発環境とは異なる戦略が必要です。なぜなら、開発環境で構成したdevServerは本番環境では機能しないためです。
本番環境でのクロスオリジンリクエスト処理には、以下のいくつかの方法があります:
- Nginx
- Node
- Nginx + Node
- サーバー側のCORS設定(多くの場合、バックエンド側はCORSを設定しないため、ここでは説明を省略します)
Nginx
Nginxのみを使用する場合、Nginxはウェブページをホストするだけでなく、プロキシサーバーとしてインターフェースリクエストも処理します。この構成により、フロントエンドアプリケーションとバックエンドサービス間のインタラクションが同一オリジンのように見え、ブラウザのクロスオリジン制限を回避できます。
まずフロントエンドの静的リソースをビルドし、クラウドサーバーにアップロードします。
次に、nginxの設定ファイル/etc/nginx/nginx.confを修正し、nginxを再起動します。
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /home/lighthouse/web-deploy-demo-2/frontend/dist;
location /api/ {
rewrite "^/api/(.*)$" /$1 break;
proxy_pass http://203.0.113.45:8081; # バックエンドサーバーのアドレスとポート
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
access_log /var/log/nginx/access.log;
}
-
/home/lighthouse/web-deploy-demo-2/frontend/distはプロジェクトビルド後のディレクトリです。 -
location /api/はプロキシ設定で、URLが/api/で始まる場合、http://203.0.113.45:8081に転送されます。
Node
Nodeのみを使用する場合、Nodeはウェブページをホストし、プロキシサーバーとしてインターフェースリクエストも処理します。
まず、静的リソースをホストするためのwebサービスプロセスを起動します。このwebサービスプロセスは、インターフェースプロキシも行うことができます。
mkdir web-service
cd web-service
npm init -y
npm install express
npm install http-proxy-middleware
vim app.js
app.jsの内容は以下の通りで、それぞれウェブページのホストとインターフェースプロキシを実装しています。
const path = require('path');
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
// 静的リソースのホスト
app.use(express.static(path.resolve(__dirname, 'dist')));
// インターフェースプロキシ
app.use('/api', createProxyMiddleware({
target: 'http://203.0.113.45:8081',
pathRewrite: {
'^/api': '' // パスを書き換え、/apiプレフィックスを削除
},
changeOrigin: true
}));
app.listen(3000, () => {
console.log(`サーバーが起動しました。ポート: 3000`);
});
Nginx + Node
NginxとNode.jsを組み合わせて使用することは、より推奨されるデプロイメント方式です。Nginxは非常に強力な処理性能を持ち、Nodeを通じてより柔軟な実装が可能になります。
- Nginxはインターフェースプロキシを担当
- Nodeは静的リソースのホストを担当
具体的な実装方案は以下の通りです。ユーザーがアクセスするエントリーポイントはNginxプロセスであり、Nginxはインターフェースプロキシだけでなく、フロントエンドリソースのアクセスリクエストをホストするサービスにプロキシします。
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# root /usr/share/nginx/html;
# root /home/lighthouse/web-deploy-demo-2/frontend/dist;
# デフォルトサーバーブロックの設定ファイルを読み込む。
include /etc/nginx/default.d/*.conf;
location /api/ {
rewrite "^/api/(.*)$" /$1 break;
proxy_pass http://203.0.113.45:8081; # バックエンドサーバーのアドレスとポート
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://203.0.113.45:3000; # フロントエンドwebサーバーのホストアドレスとポート
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
access_log /var/log/nginx/access.log;
}
このデモンストレーションコードはGitHubにアップロードされており、cloneして直接実行できます。
git clone https://github.com/baburwang/web-deploy-demo-2.git
cd web-deploy-demo-2
sh deploy.sh
ドメインバインディング
ドメインバインディングのプロセスは比較的簡単です。ドメインを購入した後、クラウドサーバーでドメイン解決を選択するだけで、ドメイン経由でアクセスできるようになります。
注意点として、ドメイン登録が完了していない場合、アクセス時にブロックされる可能性があります。