首页 > 解决方案 > 使用 React 和 Django 时发布 http://localhost:8000/api/posts/action/ 400(错误请求)

问题描述

我正在尝试使用 React 和 Django 构建一个全栈应用程序。我正在从 Django 服务器向 React 发送一个 API 请求。这是我的代码:

帖子/component.js:

import React, {useEffect, useState}  from 'react'

import {
  apiPostAction,
  apiPostCreate, 
  apiPostList} from './lookup'

export function PostsComponent(props) {
    const textAreaRef = React.createRef()
    const [newPosts, setNewPosts] = useState([])
    
    const handleBackendUpdate = (response, status) =>{
      // backend api response handler
      let tempNewPosts = [...newPosts]
      if (status === 201){
        tempNewPosts.unshift(response)
        setNewPosts(tempNewPosts)
      } else {
        console.log(response)
        alert("An error occured please try again")
      }
    }

    const handleSubmit = (event) => {
      event.preventDefault()
      const newVal = textAreaRef.current.value
      // backend api request
      apiPostCreate(newVal, handleBackendUpdate)
      textAreaRef.current.value = ''
    }
    return <div className={props.className}>
            <div className='col-12 mb-3'>
              <form onSubmit={handleSubmit}>
                <textarea ref={textAreaRef} required={true} className='form-control' name='post'>

                </textarea>
                <button type='submit' className='btn btn-primary my-3'>Post</button>
            </form>
            </div>
        <PostsList newPosts={newPosts} />
    </div>
}

export function PostsList(props) {
    const [postsInit, setPostsInit] = useState([])
    const [posts, setPosts] = useState([])
    const [postsDidSet, setPostsDidSet] = useState(false)
    useEffect(()=>{
      const final = [...props.newPosts].concat(postsInit)
      if (final.length !== posts.length) {
        setPosts(final)
      }
    }, [props.newPosts, posts, postsInit])

    useEffect(() => {
      if (postsDidSet === false){
        const handlePostListLookup = (response, status) => {
          if (status === 200){
            setPostsInit(response)
            setPostsDidSet(true)
          } else {
            alert("There was an error")
          }
        }
        apiPostList(handlePostListLookup)
      }
    }, [postsInit, postsDidSet, setPostsDidSet])


    const handleDidRepost = (newPost) => {
      const updatePostsInit = [...postsInit]
      updatePostsInit.unshift(newPost)
      setPostsInit(updatePostsInit)
      const updateFinalPosts = [...posts]
      updateFinalPosts.unshift(posts)
      setPosts(updateFinalPosts)
    }
    return posts.map((item, index)=>{
      return <Post  
        post={item} 
        didRepost={handleDidRepost}
        className='my-5 py-5 border bg-white text-dark' 
        key={`${index}-{item.id}`} />
    })
  }


export function ActionBtn(props) {
    const {post, action, didPerformAction} = props
    const likes = post.likes ? post.likes : 0
    const className = props.className ? props.className : 'btn btn-primary btn-sm'
    const actionDisplay = action.display ? action.display : 'Action'
    
    const handleActionBackendEvent = (response, status) =>{
      console.log(response, status)
      if ((status === 200 || status === 201) && didPerformAction){
        didPerformAction(response, status)
      }
    }
    const handleClick = (event) => {
      event.preventDefault()
      apiPostAction(post.id, action.type, handleActionBackendEvent)
        
    }
    const display = action.type === 'like' ? `${likes} ${actionDisplay}` : actionDisplay
    return <button className={className} onClick={handleClick}>{display}</button>
  }
  
export function ParentPost(props){
  const {post} = props
  return post.parent ? <div className='row'>
  <div className='col-11 mx-auto p-3 border rounded'>
    <p className='mb-0 text-muted small'>Repost</p>
    <Post hideActions className={' '} post={post.parent} />
  </div>
  </div> : null
}
export function Post(props) {
    const {post, didRepost, hideActions} = props
    const [actionPost, setActionPost] = useState(props.post ? props.post : null)
    const className = props.className ? props.className : 'col-10 mx-auto col-md-6'
    
    const handlePerformAction = (newActionPost, status) => {
      if (status === 200){
        setActionPost(newActionPost)
      } else if (status === 201) {
        if (didRepost){
          didRepost(newActionPost)
        }
      }
      
    }
    
    return <div className={className}>
            <div>
              <p>{post.id} - {post.content}</p>
              <ParentPost post={post} />
            </div>
        {(actionPost && hideActions !== true) && <div className='btn btn-group'>
                <ActionBtn post={actionPost} didPerformAction={handlePerformAction} action={{type: "like", display:"Likes"}}/>
                <ActionBtn post={actionPost} didPerformAction={handlePerformAction} action={{type: "unlike", display:"Unlike"}}/>
                <ActionBtn post={actionPost} didPerformAction={handlePerformAction} action={{type: "repost", display:"Repost"}}/>
              </div>
      }
    </div>
  }

帖子/lookup.js:

import {backendLookup} from '../lookup'

export function apiPostCreate(newPost, callback){
    backendLookup("POST", "/posts/create/", callback, {content: newPost})
  }

export function apiPostAction(postId, action, callback){
    const data = {id: postId, action: action}
    backendLookup("POST", "/posts/action/", callback, data)
}
  
export function apiPostList(callback) {
    backendLookup("GET", "/posts/", callback)
}

查找/component.js:

function getCookie(name) {
  var cookieValue = null;
  if (document.cookie && document.cookie !== '') {
      var cookies = document.cookie.split(';');
      for (var i = 0; i < cookies.length; i++) {
          var cookie = cookies[i].trim();
          // Does this cookie string begin with the name we want?
          if (cookie.substring(0, name.length + 1) === (name + '=')) {
              cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
              break;
          }
      }
  }
  return cookieValue;
}

export function backendLookup(method, endpoint, callback, data) {
  let jsonData;
  if (data){
    jsonData = JSON.stringify(data)
  }
  const xhr = new XMLHttpRequest()
  const url = `http://localhost:8000/api${endpoint}`
  xhr.responseType = "json"
  const csrftoken = getCookie('csrftoken');
  xhr.open(method, url)
  xhr.setRequestHeader("Content-Type", "application/json")

  if (csrftoken){
    xhr.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest")
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
    xhr.setRequestHeader("X-CSRFToken", csrftoken)
  }

  // xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
  // xhr.setRequestHeader("X-CSRFToken", csrftoken)

  xhr.onload = function() {
    callback(xhr.response, xhr.status)
  }
  xhr.onerror = function (e) {
    console.log(e)
    callback({"message": "The request was an error"}, 400)
  }
  xhr.send(jsonData)

}

此外,当我运行服务器端时,它在 Django 上运行良好。当我在我的 React localhost 上并尝试在提交后在文本字段中提交一些文本时,没有发送任何内容。当我 console.log() 它显示在输入一些文本内容后 = null 被发送。另外,当我点击“重新发布”按钮时。我在控制台中收到此错误:components.js:45 POST http://localhost:8000/api/posts/action/ 400 (Bad Request)

有任何想法吗?为什么我的 POST 请求错误?

标签: djangoreactjspost

解决方案


推荐阅读