Добрый день всем, я столкнулся с проблемой, когда начал создавать промежуточное программное обеспечение авторизации, чтобы каждый сервис при общении имел в заголовках токен авторизации пользователя и его идентификатор. Проблема возникла, когда я попытался отправить некоторые данные JSON в почтовом запросе.
При отправке прямого запроса к конечному сервису (пользователю) через POST с передачей параметров, я получаю корректный ответ.
При отправке запроса через промежуточное ПО авторизации у меня происходит бесконечная загрузка.
Если мы используем "data = request.get_json()" (строка 19 в main.py) - код работает и выдает ответ, но без данных json.
Если мы не передаем ничего в json, я получаю ошибку в main.py:
Error handling POST: 400 Bad Request: Failed to decode JSON object: Expecting value: line 1 column 1 (char 0)
Нет разницы, отправлять через postman или через curl.
Код
Node.JS Auth Service main.js:
const express = require('express');
const axios = require('axios');
const app = express();
const services = require('./services');
app.use(express.json());
async function validateToken(authToken) {
const user_service = services.find((service) => {
return service.name === 'user';
});
const user_service_url = `${user_service.protocol}://${user_service.host}:${user_service.port}`;
const request_url = `${user_service_url}/validate_token`;
try {
console.log(`Making request to ${request_url} with token ${authToken}`);
const response = await axios.post(request_url, {}, { headers: { Authorization: authToken } });
return response.data;
} catch (error) {
console.log(error);
return null;
}
}
app.get('*', async (req, res) => {
let url = req.url;
if (url.indexOf('/auth/') !== 0) {
return res.send('Authentication not completed!');
}
url = url.split('/auth')[1];
const service = services.find((service) => {
return url.indexOf(`/${service.name}`) === 0;
});
if (!service) {
return res.send('Service not found!');
}
const servicePath = `/${service.name}`;
const urlParts = url.split(servicePath);
if (urlParts.length < 2) {
return res.send('Invalid URL format');
}
const requestPath = urlParts.slice(1).join(servicePath);
const request_url = `${service.protocol}://${service.host}:${service.port}${requestPath}`;
// Check if the request has a token
if (req.headers.authorization) {
let response = await validateToken(req.headers.authorization);
if (!response.token_valid) {
req.headers.authorization = null;
} else {
req.headers.Userid = response.user_id;
console.log(response);
}
}
try {
const response = await axios.get(request_url, { headers: req.headers });
res.send(response.data);
} catch (error) {
res.status(500).send('Error while making the request');
console.log(error);
}
});
app.post('*', async (req, res) => {
let url = req.url;
if (url.indexOf('/auth/') !== 0) {
return res.send('Authentication not completed!');
}
url = url.split('/auth')[1];
const service = services.find((service) => {
return url.indexOf(`/${service.name}`) === 0;
});
if (!service) {
return res.send('Service not found!');
}
const servicePath = `/${service.name}`;
const urlParts = url.split(servicePath);
if (urlParts.length < 2) {
return res.send('Invalid URL format');
}
const requestPath = urlParts.slice(1).join(servicePath);
const request_url = `${service.protocol}://${service.host}:${service.port}${requestPath}`;
// Check if the request has a token
if (req.headers.authorization) {
let response = await validateToken(req.headers.authorization);
if (!response.token_valid) {
req.headers.authorization = null;
} else {
req.headers.Userid = response.user_id;
console.log(response);
}
}
let modifiedHeaders = {...req.headers};
delete modifiedHeaders.host;
try {
console.log("Making POST request to Flask:", request_url, req.body, modifiedHeaders);
const response = await axios.post(request_url, req.body, {
headers: modifiedHeaders,
params: req.query
});
console.log("Response from Flask:", response.status, response.data);
res.send(response.data);
} catch (error) {
console.error("Error making POST request to Flask:", error);
res.status(500).send('Error while making the request');
}
});
app.listen(services[0].port, () => {
console.log(`Example app listening on port ${services[0].port}!`);
});
Node.js services.js:
const services = [
{
name: 'auth',
protocol: 'http',
host: '127.0.0.1',
port: 3000,
},
{
name: 'weather',
protocol: 'http',
host: '127.0.0.1',
port: 3001,
},
{
name: 'routes',
protocol: 'http',
host: '127.0.0.1',
port: 3002,
},
{
name: 'places',
protocol: 'http',
host: '127.0.0.1',
port: 3003,
},
{
name: 'travel',
protocol: 'http',
host: '127.0.0.1',
port: 3004,
},
{
name: 'community',
protocol: 'http',
host: '127.0.0.1',
port: 3005,
},
{
name: 'support',
protocol: 'http',
host: '127.0.0.1',
port: 3006,
},
{
name: 'reviews',
protocol: 'http',
host: '127.0.0.1',
port: 3007,
},
{
name: 'user',
protocol: 'http',
host: '127.0.0.1',
port: 3008,
},
{
name: 'dwelling',
protocol: 'http',
host: '127.0.0.1',
port: 3009,
},
{
name: 'search',
protocol: 'http',
host: '127.0.0.1',
port: 3010,
},
{
name: 'recommendation',
protocol: 'http',
host: '127.0.0.1',
port: 3011,
},
{
name: 'notification',
protocol: 'http',
host: '127.0.0.1',
port: 3012,
},
{
name: 'transport',
protocol: 'http',
host: '127.0.0.1',
port: 3013,
}
]
module.exports = services;
Python Flask main.py:
from flask import request, jsonify, Flask
from flask_cors import CORS
app = Flask(__name__)
# CORS(allow_headers='Content-Type')
# CORS(app, resources={r"/*": {"origins": "*"}})
@app.route('/user', methods=['GET'])
def get_user():
return jsonify({'user_id': request.headers.get('Userid'), 'token': request.headers.get('Authorization')})
@app.route('/user', methods=['POST'])
def create_user():
try:
print('Handling POST request')
data = request.get_json()
print('Data received:', data)
return jsonify({'user_id': request.headers.get('Userid'), 'token': request.headers.get('Authorization')})
except Exception as e:
print("Error handling POST:", str(e))
return jsonify({'error': str(e)}), 500
@app.route('/user', methods=['PUT'])
def update_user():
return jsonify({'user_id': request.headers.get('Userid'), 'token': request.headers.get('Authorization')})
@app.route('/user', methods=['DELETE'])
def delete_user():
return jsonify({'user_id': request.headers.get('Userid'), 'token': request.headers.get('Authorization')})
@app.route('/validate_token', methods=['POST'])
def validate_token():
token = request.headers.get('Authorization')
# TODO: Real validate token logic
if token is None:
return jsonify({'user_id': None, 'token_valid': False})
elif token == 'test':
return jsonify({'user_id': 1, 'token_valid': True})
else:
return jsonify({'user_id': None, 'token_valid': False})
if __name__ == '__main__':
app.run(host='127.0.0.1', port=3008, debug=True, threaded=False)
Если мы используем метод get — все ок (но без тела json), а также если мы не используем службу аутентификации и делаем прямой запрос к серверу flask (но в этом случае я не могу получить идентификатор пользователя и токен аутентификации)