前端用$.getJSON传含URL参数至Django后端遇404问题求助
你的问题核心在于Django路由对路径参数的解析逻辑和URL编码后的处理冲突了,我来一步步帮你理清并解决:
为什么会出现404?
你前端用encodeURIComponent把URL转成了类似http%3A%2F%2Fexample.com的格式,但Django在处理请求URL时,会自动对整个URL进行URL解码——也就是说%2F会被还原成/。
而你定义的path路由里,<url>参数默认使用的是str转换器,这个转换器的规则是不匹配路径分隔符/。解码后的URL里的/会把原本的路径拆分成更多段,比如你的请求路径会变成:/updateAssignment/1/xxx/2024/xxx/http://example.com/xxx/...
Django会把http:、//example.com当成单独的参数段,和你定义的12个参数的路由完全不匹配,自然就返回404了。
解决方案(按推荐程度排序)
方案1:改用查询字符串传递参数(最推荐)
把URL这类含特殊字符的参数从路径里移到查询字符串(GET参数)中,这是更符合HTTP规范的做法,也能彻底避免路径匹配问题。
后端修改urls.py:
简化路由,只保留必要的标识参数(比如assignmentId):
path("updateAssignment/<int:iD>/", Dashboard.update_assignment, name="updateAssignment")
前端修改JS代码:
不用手动拼接路径,直接用jQuery的getJSON的第二个参数传递键值对,jQuery会自动帮你编码参数:
function updateAssignment(assignmentId){ const assignmentUpdateEndpoint = `/updateAssignment/${assignmentId}/`; // 把所有参数整理成对象 const params = { body: document.getElementById(`Assignment-Body${assignmentId}`).value, deadline: document.getElementById(`Assignment-Deadline${assignmentId}`).value, user: document.getElementById(`Assignment-User${assignmentId}`).value, url: document.getElementById(`Assignment-URL${assignmentId}`).value, game: document.getElementById(`Assignment-Game${assignmentId}`).value, additionalKeywords: document.getElementById(`Assignment-Additional-Keywords${assignmentId}`).value, seoTitle: document.getElementById(`Assignment-SEOtitle${assignmentId}`).value, payment: document.getElementById(`Assignment-Payment${assignmentId}`).value, wordCount: document.getElementById(`Assignment-WordCount${assignmentId}`).value, category: document.getElementById(`Assignment-Category${assignmentId}`).value, state: document.getElementById(`Assignment-State${assignmentId}`).value }; $.getJSON(assignmentUpdateEndpoint, params).done((response) => { // 处理响应逻辑 }); }
后端视图获取参数:
在update_assignment视图里,通过request.GET获取参数:
def update_assignment(request, iD): url = request.GET.get('url') body = request.GET.get('body') # 其他参数同理... # 业务逻辑处理
方案2:使用正则路由(re_path)匹配含/的参数
如果你坚持要把URL放在路径参数里,可以用re_path自定义正则表达式,让<url>参数能匹配包含/的内容。
修改urls.py:
from django.urls import re_path re_path( r"updateAssignment/(?P<iD>[^/]+)/(?P<body>[^/]+)/(?P<deadline>[^/]+)/(?P<user>[^/]+)/(?P<url>.+)/(?P<game>[^/]+)/(?P<aK>[^/]+)/(?P<seoTitle>[^/]+)/(?P<payment>[^/]+)/(?P<wordCount>[^/]+)/(?P<category>[^/]+)/(?P<state>[^/]+)/", Dashboard.update_assignment, name="updateAssignment" )
这里(?P<url>.+)的正则会匹配任意字符(包括/),这样就能正确捕获解码后的完整URL参数。
⚠️ 注意:这个方案有个隐患——如果url参数后面的其他参数里也出现/,会导致参数匹配混乱,所以只适合你能确保后续参数不含/的场景。
方案3:自定义Django路径转换器
另一种更优雅的路径参数方案是自定义转换器,让它支持匹配包含/的内容:
- 在项目中创建
custom_converters.py文件:
from django.urls.converters import StringConverter class URLConverter(StringConverter): regex = r'.+' # 匹配任意字符,包括路径分隔符/
- 在
urls.py中注册并使用这个转换器:
from django.urls import path, register_converter from .custom_converters import URLConverter # 注册自定义转换器 register_converter(URLConverter, 'url') # 修改路由,使用<url:url>来匹配URL参数 path( "updateAssignment/<iD>/<body>/<deadline>/<user>/<url:url>/<game>/<aK>/<seoTitle>/<payment>/<wordCount>/<category>/<state>/", Dashboard.update_assignment, name="updateAssignment" )
这样<url:url>就会使用自定义的转换器,正确捕获包含/的URL参数。
总结
优先选择方案1(查询字符串),它不仅能解决当前的404问题,还让你的API设计更规范、更易维护。如果因为某些原因必须用路径参数,再考虑方案2或3。
内容的提问来源于stack exchange,提问作者Kamil Bialomazur

