У меня возникла странная проблема в моем проекте: мне не удалось найти, что я сделал не так. Я пытаюсь загрузить изображение в свой блог, и для этого я использую конфигурацию aws s3. Я считаю, что мои конфиги исправлены, но на всякий случай добавлю их туда:
вот моя конфигурация корса
<?xml version = "1.0" encoding = "UTF-8"?>
<CORSConfiguration xmlns = "http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
<CORSRule>
<AllowedOrigin>http://localhost:3000</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
вся моя политика IAM и пользовательский api в порядке и активированы. Вот код в моем бэкэнде:
const s3 = new AWS.S3({
accessKeyId: keys.aws.clientID,
secretAccessKey: keys.aws.clientSecret,
signatureVersion: "v4",
region: "eu-west-3"
})
const router = express.Router()
// @route GET api/posts/upload
// @desc Upload an image on amazone server API
// @access Private
router.get(
"/upload",
passport.authenticate("jwt", { session: false }),
(req, res) => {
const key = `${req.user.id}/${uuid()}.jpeg`
s3.getSignedUrl(
"putObject",
{
Bucket: "bebeyogini",
ContentType: "image/jpeg",
Key: key
},
(err, url) => res.send({ key, url })
)
}
)
Когда я вызываю конечную точку / upload, она возвращает
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your key and signing method.
</Message>
вот почему в моем интерфейсе (в сокращении) я добавил PUT, где я добавляю файл типа содержимого в заголовки. Но все равно это не работает в этом проекте
export const sendPost = (newPost, file, history) => async dispatch => {
dispatch(loading())
const uploadConfig = await axios.get("/api/posts/upload")
console.info(uploadConfig)
console.info(uploadConfig.data)
await axios.put(uploadConfig.data.url, file, {
headers: {
"Content-Type": file.type
}
})
const res = await axios.post("/api/posts", {
...newPost,
imageUrl: uploadConfig.data.key
})
history.push("/dashboard")
dispatch({
type: POSTS_FETCHED,
payload: res.data
})
}
Мне удалось несколько месяцев назад в другом проекте заставить aws s3 работать с той же конфигурацией, и единственное различие, которое у меня было между обоими, заключается в том, что тот, который работал, был настроен с сеансом cookie, а это - токен jwt в заголовке .
Если у кого-то есть идея ... Я полностью застрял! здесь репозиторий
статус ошибок:
bebeyogini.s3.eu-west-3.amazonaws.com/5bc0eca10743075fecb360f2/8bb4ff60-d8e7-11e8-ad9d-f776f418fd42.jpeg?Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIAMYTIX267RJ5E4A%2F20181026%2Feu-west-3%2Fs3%2Faws4_request&X-Amz-Date=20181026T062242Z&X-Amz-Expires=900&X-Amz-Signature=943652af4bea7e8e0e6d0f97503ea997817e7d68e0540c599643d612d71fe693&X-Amz-SignedHeaders=host:1 PUT https://bebeyogini.s3.eu-west-3.amazonaws.com/5bc0eca10743075fecb360f2/8bb4ff60-d8e7-11e8-ad9d-f776f418fd42.jpeg?Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIAMYTIX267RJ5E4A%2F20181026%2Feu-west-3%2Fs3%2Faws4_request&X-Amz-Date=20181026T062242Z&X-Amz-Expires=900&X-Amz-Signature=943652af4bea7e8e0e6d0f97503ea997817e7d68e0540c599643d612d71fe693&X-Amz-SignedHeaders=host 400 (Bad Request)
createError.js:17 Uncaught (in promise) Error: Request failed with status code 400
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:78)
Я обновил сообщение со статусом ошибок ...
The request signature we calculated does not match the signature you provided. Check your key and signing method.
это означает, что ваши данные предварительной подписи не совпадают с данными, которые вы хотите загрузить.
Ваши подписанные данные:
{
Key: `${req.user.id}/${uuid()}.jpeg`
ContentType: "image/jpeg",
}
Мета вашего файла:
{
Name: file.name
ContentType: "image/jpeg",
}
file.name
! == ${req.user.id}/${uuid()}.jpeg
Вы можете изменить имя файла на стороне клиента на то же имя файла (которое было сгенерировано) на стороне сервера или использовать противоположный способ
Понятно, это многое объяснило бы! Я постараюсь обновить это прямо сейчас!
Что ж, я смотрю и просто не могу понять, как вы могли сказать, что моя мета файла - это file.name, я проверял снова и снова, и я не знаю, что вы имеете в виду под Name: file.name
Функция sendPost
в вашем интерфейсе, второй параметр - file
. Это файловый объект, file.name
- это исходное имя файла (то, что было загружено с вашего компьютера).
Хорошо, в действии функция PUT, которую я использую в качестве первого аргумента uploadConfig.data.url, где я предполагаю загрузить данные, а затем вы говорите, что во втором аргументе, который является файлом, он автоматически обнаруживает событие file.name я не хочу, чтобы он это делал? Я попытался установить такое же имя в бэкэнде, преобразовав ключ = 'test.jpeg' и импортировав изображение с именем 'test.jpeg', чтобы оно соответствовало этому имени файла, но у меня была такая же ошибка.
Дело в том, что с использованием точно такого же пользовательского интерфейса и бэкэнда, но с настройкой аутентификации с использованием файлов cookie, а не токена jwt, он отлично работает. Но я хочу jwt, потому что я не хочу делать это только на навигаторах ... Я не знаю почему, но я думаю, что заголовки авторизации делают что-то странное, и aws s3 это не нравится.
Хорошо, после нескольких ночей страданий я нашел решение проблемы. Имейте в виду, что AWS S3 не принимает токен-носитель jwt, включенный в его запрос PUT. Поэтому вам нужно отключить его при выполнении запроса. Здесь я мог бы исправить это на моем фронте с помощью библиотеки axios ...
export const sendPost = (values, file, history) => async dispatch => {
dispatch(loading())
const uploadConfig = await axios.get("/api/posts/upload")
delete axios.defaults.headers.common["Authorization"]
await axios.put(uploadConfig.data.url, file, {
headers: {
ContentType: file.type
}
})
const token = localStorage.getItem("jwtToken")
axios.defaults.headers.common["Authorization"] = token
const res = await axios.post("/api/posts", {
...values,
imageUrl: uploadConfig.data.key
})
dispatch({
type: POSTS_FETCHED,
payload: res.data
})
history.push("/dashboard")
}
Это решило мои проблемы. Я использовал встроенный в Nuxt модуль $axios
, который включает заголовки Authorization
. Мне пришлось импортировать и создать новый экземпляр axios.
это сэкономило мне время.
это потенциально сэкономило мне часы и часы работы. Спасибо.
400 имеет ряд потенциальных причин, задокументированных в docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html